From e1673e4c0ca89153e26d31cd783f0f8260c6d0fb Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Mon, 19 Aug 2024 14:50:26 +0300 Subject: [PATCH 001/406] fix(build): IDF release/v5.3 466a392a and initial changes --- .github/scripts/on-release.sh | 20 +- .github/workflows/push.yml | 43 +- .gitignore | 1 + CMakeLists.txt | 6 +- cores/esp32/Client.h | 2 + cores/esp32/HWCDC.cpp | 16 +- cores/esp32/HardwareSerial.cpp | 24 +- cores/esp32/HardwareSerial.h | 12 +- cores/esp32/esp32-hal-i2c-slave.c | 30 +- cores/esp32/esp32-hal-touch.c | 36 +- cores/esp32/esp32-hal-touch.h | 10 +- cores/esp32/esp32-hal-uart.c | 46 +- idf_component.yml | 2 +- .../SerialToSerialBT_Legacy.ino | 7 - .../SerialToSerialBT_SSP.ino | 5 - .../BluetoothSerial/src/BluetoothSerial.cpp | 15 - .../BluetoothSerial/src/BluetoothSerial.h | 5 - .../Serial_STD_Func_OnReceive.ino | 10 +- libraries/ESP_I2S/src/ESP_I2S.cpp | 2 +- libraries/ESP_I2S/src/ESP_I2S.h | 2 +- libraries/Ethernet/src/ETH.cpp | 5 + .../DiagnosticsSmokeTest.ino | 3 +- libraries/Network/src/NetworkClient.h | 2 - libraries/PPP/src/PPP.cpp | 2 +- package/package_esp32_index.template.json | 538 +++++++----------- platform.txt | 6 +- tests/validation/uart/uart.ino | 60 +- 27 files changed, 368 insertions(+), 542 deletions(-) diff --git a/.github/scripts/on-release.sh b/.github/scripts/on-release.sh index eb8f2be7b81..3c3cfc05895 100755 --- a/.github/scripts/on-release.sh +++ b/.github/scripts/on-release.sh @@ -219,12 +219,8 @@ find "$PKG_DIR" -name '*.git*' -type f -delete ## RVTC_NAME="riscv32-esp-elf-gcc" RVTC_NEW_NAME="esp-rv32" -X32TC_NAME="xtensa-esp32-elf-gcc" +X32TC_NAME="xtensa-esp-elf-gcc" X32TC_NEW_NAME="esp-x32" -XS2TC_NAME="xtensa-esp32s2-elf-gcc" -XS2TC_NEW_NAME="esp-xs2" -XS3TC_NAME="xtensa-esp32s3-elf-gcc" -XS3TC_NEW_NAME="esp-xs3" # Replace tools locations in platform.txt echo "Generating platform.txt..." @@ -233,9 +229,7 @@ sed "s/version=.*/version=$RELEASE_TAG/g" | \ sed 's/tools\.esp32-arduino-libs\.path\.windows=.*//g' | \ sed 's/{runtime\.platform\.path}.tools.esp32-arduino-libs/\{runtime.tools.esp32-arduino-libs.path\}/g' | \ sed 's/{runtime\.platform\.path}.tools.xtensa-esp-elf-gdb/\{runtime.tools.xtensa-esp-elf-gdb.path\}/g' | \ -sed "s/{runtime\.platform\.path}.tools.xtensa-esp32-elf/\\{runtime.tools.$X32TC_NEW_NAME.path\\}/g" | \ -sed "s/{runtime\.platform\.path}.tools.xtensa-esp32s2-elf/\\{runtime.tools.$XS2TC_NEW_NAME.path\\}/g" | \ -sed "s/{runtime\.platform\.path}.tools.xtensa-esp32s3-elf/\\{runtime.tools.$XS3TC_NEW_NAME.path\\}/g" | \ +sed "s/{runtime\.platform\.path}.tools.xtensa-esp-elf/\\{runtime.tools.$X32TC_NEW_NAME.path\\}/g" | \ sed 's/{runtime\.platform\.path}.tools.riscv32-esp-elf-gdb/\{runtime.tools.riscv32-esp-elf-gdb.path\}/g' | \ sed "s/{runtime\.platform\.path}.tools.riscv32-esp-elf/\\{runtime.tools.$RVTC_NEW_NAME.path\\}/g" | \ sed 's/{runtime\.platform\.path}.tools.esptool/\{runtime.tools.esptool_py.path\}/g' | \ @@ -355,15 +349,7 @@ rvtc_jq_arg="\ (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$X32TC_NAME\")).version = \"$RVTC_VERSION\" |\ (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$X32TC_NAME\")).name = \"$X32TC_NEW_NAME\" |\ (.packages[0].tools[] | select(.name==\"$X32TC_NAME\")).version = \"$RVTC_VERSION\" |\ - (.packages[0].tools[] | select(.name==\"$X32TC_NAME\")).name = \"$X32TC_NEW_NAME\" |\ - (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$XS2TC_NAME\")).version = \"$RVTC_VERSION\" |\ - (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$XS2TC_NAME\")).name = \"$XS2TC_NEW_NAME\" |\ - (.packages[0].tools[] | select(.name==\"$XS2TC_NAME\")).version = \"$RVTC_VERSION\" |\ - (.packages[0].tools[] | select(.name==\"$XS2TC_NAME\")).name = \"$XS2TC_NEW_NAME\" |\ - (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$XS3TC_NAME\")).version = \"$RVTC_VERSION\" |\ - (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$XS3TC_NAME\")).name = \"$XS3TC_NEW_NAME\" |\ - (.packages[0].tools[] | select(.name==\"$XS3TC_NAME\")).version = \"$RVTC_VERSION\" |\ - (.packages[0].tools[] | select(.name==\"$XS3TC_NAME\")).name = \"$XS3TC_NEW_NAME\"" + (.packages[0].tools[] | select(.name==\"$X32TC_NAME\")).name = \"$X32TC_NEW_NAME\"" cat "$PACKAGE_JSON_TEMPLATE" | jq "$rvtc_jq_arg" > "$OUTPUT_DIR/package-$LIBS_PROJ_NAME-rvfix.json" PACKAGE_JSON_TEMPLATE="$OUTPUT_DIR/package-$LIBS_PROJ_NAME-rvfix.json" diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 2f14a6fb62f..251d787dfd9 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -194,28 +194,29 @@ jobs: - name: Build Sketches run: bash ./.github/scripts/on-push.sh - # PlatformIO on Windows, Ubuntu and Mac - build-platformio: - name: PlatformIO on ${{ matrix.os }} - needs: gen-chunks - if: | - needs.gen-chunks.outputs.build_all == 'true' || - needs.gen-chunks.outputs.build_static_sketches == 'true' || - needs.gen-chunks.outputs.build_platformio == 'true' - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] + # # PlatformIO on Windows, Ubuntu and Mac + # build-platformio: + # name: PlatformIO on ${{ matrix.os }} + # needs: gen-chunks + # if: | + # needs.gen-chunks.outputs.build_all == 'true' || + # needs.gen-chunks.outputs.build_static_sketches == 'true' || + # needs.gen-chunks.outputs.build_platformio == 'true' + # runs-on: ${{ matrix.os }} + # strategy: + # fail-fast: false + # matrix: + # os: [ubuntu-latest, windows-latest, macOS-latest] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.x' - - name: Build Sketches - run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO + # steps: + # - uses: actions/checkout@v4 + # - uses: actions/setup-python@v5 + # with: + # python-version: '3.x' + # - name: Build Sketches + # run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO + # ESP-IDF component build build-esp-idf-component: name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }} needs: gen-chunks @@ -231,7 +232,7 @@ jobs: # See https://hub.docker.com/r/espressif/idf/tags and # https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html # for details. - idf_ver: ["release-v5.1"] + idf_ver: ["release-v5.3"] idf_target: ["esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2"] container: espressif/idf:${{ matrix.idf_ver }} steps: diff --git a/.gitignore b/.gitignore index 1519de52764..d254d439834 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ tools/esp32-arduino-libs +tools/xtensa-esp-elf tools/xtensa-esp32-elf tools/xtensa-esp32s2-elf tools/xtensa-esp32s3-elf diff --git a/CMakeLists.txt b/CMakeLists.txt index a11d4809049..252059a8907 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,8 @@ # export ARDUINO_SKIP_IDF_VERSION_CHECK=1 # idf.py build -set(min_supported_idf_version "5.1.0") -set(max_supported_idf_version "5.1.99") +set(min_supported_idf_version "5.3.0") +set(max_supported_idf_version "5.3.99") set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}") if ("${idf_version}" AND NOT "$ENV{ARDUINO_SKIP_IDF_VERSION_CHECK}") @@ -293,7 +293,7 @@ endforeach() set(includedirs variants/${CONFIG_ARDUINO_VARIANT}/ cores/esp32/ ${ARDUINO_LIBRARIES_INCLUDEDIRS}) set(srcs ${CORE_SRCS} ${ARDUINO_LIBRARIES_SRCS}) set(priv_includes cores/esp32/libb64) -set(requires spi_flash esp_partition mbedtls wpa_supplicant esp_adc esp_eth http_parser espressif__network_provisioning) +set(requires spi_flash esp_partition mbedtls wpa_supplicant esp_adc esp_eth http_parser esp_ringbuf esp_driver_gptimer esp_driver_usb_serial_jtag driver espressif__network_provisioning) set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support bt esp_hid usb esp_psram ${ARDUINO_LIBRARIES_REQUIRES}) if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_OpenThread) diff --git a/cores/esp32/Client.h b/cores/esp32/Client.h index ab013612401..4ea10d070fb 100644 --- a/cores/esp32/Client.h +++ b/cores/esp32/Client.h @@ -26,7 +26,9 @@ class Client : public Stream { public: virtual int connect(IPAddress ip, uint16_t port) = 0; + virtual int connect(IPAddress ip, uint16_t port, int32_t timeout) = 0; virtual int connect(const char *host, uint16_t port) = 0; + virtual int connect(const char *host, uint16_t port, int32_t timeout) = 0; virtual size_t write(uint8_t) = 0; virtual size_t write(const uint8_t *buf, size_t size) = 0; virtual int available() = 0; diff --git a/cores/esp32/HWCDC.cpp b/cores/esp32/HWCDC.cpp index b0f653e889e..59709fd4f86 100644 --- a/cores/esp32/HWCDC.cpp +++ b/cores/esp32/HWCDC.cpp @@ -286,14 +286,14 @@ bool HWCDC::deinit(void *busptr) { running = true; // Setting USB D+ D- pins bool retCode = true; - retCode &= perimanClearPinBus(USB_DM_GPIO_NUM); - retCode &= perimanClearPinBus(USB_DP_GPIO_NUM); + retCode &= perimanClearPinBus(USB_INT_PHY0_DM_GPIO_NUM); + retCode &= perimanClearPinBus(USB_INT_PHY0_DP_GPIO_NUM); if (retCode) { // Force the host to re-enumerate (BUS_RESET) - pinMode(USB_DM_GPIO_NUM, OUTPUT_OPEN_DRAIN); - pinMode(USB_DP_GPIO_NUM, OUTPUT_OPEN_DRAIN); - digitalWrite(USB_DM_GPIO_NUM, LOW); - digitalWrite(USB_DP_GPIO_NUM, LOW); + pinMode(USB_INT_PHY0_DM_GPIO_NUM, OUTPUT_OPEN_DRAIN); + pinMode(USB_INT_PHY0_DP_GPIO_NUM, OUTPUT_OPEN_DRAIN); + digitalWrite(USB_INT_PHY0_DM_GPIO_NUM, LOW); + digitalWrite(USB_INT_PHY0_DP_GPIO_NUM, LOW); } // release the flag running = false; @@ -323,11 +323,11 @@ void HWCDC::begin(unsigned long baud) { // delay(10); // USB Host has to enumerate it again // Peripheral Manager setting for USB D+ D- pins - uint8_t pin = USB_DM_GPIO_NUM; + uint8_t pin = USB_INT_PHY0_DM_GPIO_NUM; if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_USB_DM, (void *)this, -1, -1)) { goto err; } - pin = USB_DP_GPIO_NUM; + pin = USB_INT_PHY0_DP_GPIO_NUM; if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_USB_DP, (void *)this, -1, -1)) { goto err; } diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 1f064faada6..c1cf8200a32 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -26,23 +26,23 @@ void serialEvent(void) __attribute__((weak)); void serialEvent(void) {} -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 void serialEvent1(void) __attribute__((weak)); void serialEvent1(void) {} -#endif /* SOC_UART_NUM > 1 */ +#endif /* SOC_UART_HP_NUM > 1 */ -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 void serialEvent2(void) __attribute__((weak)); void serialEvent2(void) {} -#endif /* SOC_UART_NUM > 2 */ +#endif /* SOC_UART_HP_NUM > 2 */ #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) // There is always Seria0 for UART0 HardwareSerial Serial0(0); -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 HardwareSerial Serial1(1); #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 HardwareSerial Serial2(2); #endif @@ -72,12 +72,12 @@ void serialEventRun(void) { if (Serial0.available()) { serialEvent(); } -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 if (Serial1.available()) { serialEvent1(); } #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 if (Serial2.available()) { serialEvent2(); } @@ -279,8 +279,8 @@ void HardwareSerial::_uartEventTask(void *args) { } void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd) { - if (_uart_nr >= SOC_UART_NUM) { - log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_NUM - 1); + if (_uart_nr >= SOC_UART_HP_NUM) { + log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_HP_NUM - 1); return; } @@ -305,7 +305,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in txPin = _txPin < 0 ? (int8_t)SOC_TX0 : _txPin; } break; -#if SOC_UART_NUM > 1 // may save some flash bytes... +#if SOC_UART_HP_NUM > 1 // may save some flash bytes... case UART_NUM_1: if (rxPin < 0 && txPin < 0) { // do not change RX1/TX1 if it has already been set before @@ -314,7 +314,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in } break; #endif -#if SOC_UART_NUM > 2 // may save some flash bytes... +#if SOC_UART_HP_NUM > 2 // may save some flash bytes... case UART_NUM_2: if (rxPin < 0 && txPin < 0) { // do not change RX2/TX2 if it has already been set before diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 3fd5e7dc99b..2d280b053de 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -146,7 +146,7 @@ typedef enum { // Default pins for UART1 are arbitrary, and defined here for convenience. -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 #ifndef RX1 #if CONFIG_IDF_TARGET_ESP32 #define RX1 (gpio_num_t)26 @@ -182,11 +182,11 @@ typedef enum { #define TX1 (gpio_num_t)1 #endif #endif -#endif /* SOC_UART_NUM > 1 */ +#endif /* SOC_UART_HP_NUM > 1 */ // Default pins for UART2 are arbitrary, and defined here for convenience. -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 #ifndef RX2 #if CONFIG_IDF_TARGET_ESP32 #define RX2 (gpio_num_t)4 @@ -202,7 +202,7 @@ typedef enum { #define TX2 (gpio_num_t)20 #endif #endif -#endif /* SOC_UART_NUM > 2 */ +#endif /* SOC_UART_HP_NUM > 2 */ typedef std::function OnReceiveCb; typedef std::function OnReceiveErrorCb; @@ -357,10 +357,10 @@ extern void serialEventRun(void) __attribute__((weak)); #endif // ARDUINO_USB_CDC_ON_BOOT // There is always Seria0 for UART0 extern HardwareSerial Serial0; -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 extern HardwareSerial Serial1; #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 extern HardwareSerial Serial2; #endif #endif //!defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) diff --git a/cores/esp32/esp32-hal-i2c-slave.c b/cores/esp32/esp32-hal-i2c-slave.c index edae1e57c92..5504fd62adf 100644 --- a/cores/esp32/esp32-hal-i2c-slave.c +++ b/cores/esp32/esp32-hal-i2c-slave.c @@ -49,7 +49,7 @@ #define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 #define I2C_SCL_IDX(p) ((p == 0) ? I2CEXT0_SCL_OUT_IDX : ((p == 1) ? I2CEXT1_SCL_OUT_IDX : 0)) #define I2C_SDA_IDX(p) ((p == 0) ? I2CEXT0_SDA_OUT_IDX : ((p == 1) ? I2CEXT1_SDA_OUT_IDX : 0)) #else @@ -99,14 +99,14 @@ typedef union { uint32_t val; } i2c_slave_queue_event_t; -static i2c_slave_struct_t _i2c_bus_array[SOC_I2C_NUM] = { +static i2c_slave_struct_t _i2c_bus_array[SOC_HP_I2C_NUM] = { {&I2C0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 #if !CONFIG_DISABLE_HAL_LOCKS , NULL #endif }, -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 {&I2C1, 1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 #if !CONFIG_DISABLE_HAL_LOCKS , @@ -210,7 +210,7 @@ static bool i2cSlaveDetachBus(void *bus_i2c_num); //===================================================================================================================== esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void *arg) { - if (num >= SOC_I2C_NUM) { + if (num >= SOC_HP_I2C_NUM) { log_e("Invalid port num: %u", num); return ESP_ERR_INVALID_ARG; } @@ -224,7 +224,7 @@ esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_ca } esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len) { - if (num >= SOC_I2C_NUM) { + if (num >= SOC_HP_I2C_NUM) { log_e("Invalid port num: %u", num); return ESP_ERR_INVALID_ARG; } @@ -309,14 +309,14 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t if (i2c->num == 0) { periph_ll_enable_clk_clear_rst(PERIPH_I2C0_MODULE); -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 } else { periph_ll_enable_clk_clear_rst(PERIPH_I2C1_MODULE); #endif } i2c_ll_slave_init(i2c->dev); - i2c_ll_set_fifo_mode(i2c->dev, true); + i2c_ll_slave_set_fifo_mode(i2c->dev, true); i2c_ll_set_slave_addr(i2c->dev, slaveID, false); i2c_ll_set_tout(i2c->dev, I2C_LL_MAX_TIMEOUT); i2c_slave_set_frequency(i2c, frequency); @@ -337,13 +337,13 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK); - i2c_ll_set_fifo_mode(i2c->dev, true); + i2c_ll_slave_set_fifo_mode(i2c->dev, true); if (!i2c->intr_handle) { uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED; if (i2c->num == 0) { ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 } else { ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); #endif @@ -375,7 +375,7 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t } esp_err_t i2cSlaveDeinit(uint8_t num) { - if (num >= SOC_I2C_NUM) { + if (num >= SOC_HP_I2C_NUM) { log_e("Invalid port num: %u", num); return ESP_ERR_INVALID_ARG; } @@ -398,7 +398,7 @@ esp_err_t i2cSlaveDeinit(uint8_t num) { } size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { - if (num >= SOC_I2C_NUM) { + if (num >= SOC_HP_I2C_NUM) { log_e("Invalid port num: %u", num); return 0; } @@ -515,16 +515,16 @@ static bool i2c_slave_set_frequency(i2c_slave_struct_t *i2c, uint32_t clk_speed) i2c_hal_clk_config_t clk_cal; #if SOC_I2C_SUPPORT_APB - i2c_ll_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal); + i2c_ll_master_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal); i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_APB); /*!< I2C source clock from APB, 80M*/ #elif SOC_I2C_SUPPORT_XTAL - i2c_ll_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal); + i2c_ll_master_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal); i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_XTAL); /*!< I2C source clock from XTAL, 40M */ #endif i2c_ll_set_txfifo_empty_thr(i2c->dev, a); i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a); - i2c_ll_set_bus_timing(i2c->dev, &clk_cal); - i2c_ll_set_filter(i2c->dev, 3); + i2c_ll_master_set_bus_timing(i2c->dev, &clk_cal); + i2c_ll_master_set_filter(i2c->dev, 3); return true; } diff --git a/cores/esp32/esp32-hal-touch.c b/cores/esp32/esp32-hal-touch.c index d32b34d0173..764b7dbb73f 100644 --- a/cores/esp32/esp32-hal-touch.c +++ b/cores/esp32/esp32-hal-touch.c @@ -22,10 +22,10 @@ Internal Private Touch Data Structure and Functions */ -#if SOC_TOUCH_VERSION_1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 static uint16_t __touchSleepCycles = 0x1000; static uint16_t __touchMeasureCycles = 0x1000; -#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT; static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT; #endif @@ -37,7 +37,7 @@ typedef struct { voidFuncPtr fn; bool callWithArgs; void *arg; -#if SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3 +#if SOC_TOUCH_SENSOR_VERSION == 2 // Only for ESP32S2 and ESP32S3 bool lastStatusIsPressed; #endif } TouchInterruptHandle_t; @@ -51,7 +51,7 @@ static bool initialized = false; static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = {false}; static void ARDUINO_ISR_ATTR __touchISR(void *arg) { -#if SOC_TOUCH_VERSION_1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 uint32_t pad_intr = touch_pad_get_status(); //clear interrupt touch_pad_clear_status(); @@ -68,7 +68,7 @@ static void ARDUINO_ISR_ATTR __touchISR(void *arg) { } } } -#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 touch_pad_intr_mask_t evt = touch_pad_read_intr_status_mask(); uint8_t pad_num = touch_pad_get_current_meas_channel(); if (evt & TOUCH_PAD_INTR_MASK_ACTIVE) { @@ -93,9 +93,9 @@ static void ARDUINO_ISR_ATTR __touchISR(void *arg) { static void __touchSetCycles(uint16_t measure, uint16_t sleep) { __touchSleepCycles = sleep; __touchMeasureCycles = measure; -#if SOC_TOUCH_VERSION_1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 touch_pad_set_measurement_clock_cycles(measure); -#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 touch_pad_set_charge_discharge_times(measure); #endif touch_pad_set_measurement_interval(sleep); @@ -123,7 +123,7 @@ static void __touchInit() { esp_err_t err = ESP_OK; -#if SOC_TOUCH_VERSION_1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 err = touch_pad_init(); if (err != ESP_OK) { goto err; @@ -143,8 +143,8 @@ static void __touchInit() { if (err != ESP_OK) { goto err; } - touch_pad_intr_enable(); // returns ESP_OK -#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 + touch_pad_intr_enable(); // returns ESP_OK +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 err = touch_pad_init(); if (err != ESP_OK) { goto err; @@ -179,11 +179,11 @@ static void __touchChannelInit(int pad) { return; } -#if SOC_TOUCH_VERSION_1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 // Initial no Threshold and setup __touchInterruptHandlers[pad].fn = NULL; - touch_pad_config(pad, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK -#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 + touch_pad_config(pad, TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 // Initial no Threshold and setup __touchInterruptHandlers[pad].fn = NULL; touch_pad_config(pad); // returns ESP_OK @@ -238,7 +238,7 @@ static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Ar if (userFunc == NULL) { // detach ISR User Call __touchInterruptHandlers[pad].fn = NULL; - threshold = SOC_TOUCH_PAD_THRESHOLD_MAX; // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX + threshold = TOUCH_PAD_THRESHOLD_MAX; // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX } else { // attach ISR User Call __touchInit(); @@ -270,7 +270,7 @@ static void __touchDettachInterrupt(uint8_t pin) { External Public Touch API Functions */ -#if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC +#if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC void touchInterruptSetThresholdDirection(bool mustbeLower) { if (mustbeLower) { touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW); @@ -278,7 +278,7 @@ void touchInterruptSetThresholdDirection(bool mustbeLower) { touch_pad_set_trigger_mode(TOUCH_TRIGGER_ABOVE); } } -#elif SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3 +#elif SOC_TOUCH_SENSOR_VERSION == 2 // Only for ESP32S2 and ESP32S3 // returns true if touch pad has been and continues pressed and false otherwise bool touchInterruptGetLastStatus(uint8_t pin) { int8_t pad = digitalPinToTouchChannel(pin); @@ -307,10 +307,10 @@ void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold) { return; } } -#if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC +#if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC touch_pad_set_thresh(pad, threshold); -#elif SOC_TOUCH_VERSION_2 +#elif SOC_TOUCH_SENSOR_VERSION == 2 touch_pad_sleep_channel_enable(pad, true); touch_pad_sleep_set_threshold(pad, threshold); diff --git a/cores/esp32/esp32-hal-touch.h b/cores/esp32/esp32-hal-touch.h index db33ce3bc6a..115d6cdc9cf 100644 --- a/cores/esp32/esp32-hal-touch.h +++ b/cores/esp32/esp32-hal-touch.h @@ -29,13 +29,13 @@ extern "C" { #include "esp32-hal.h" -#if !defined(SOC_TOUCH_VERSION_1) && !defined(SOC_TOUCH_VERSION_2) +#if !SOC_TOUCH_SENSOR_SUPPORTED #error Touch IDF driver Not supported! #endif -#if SOC_TOUCH_VERSION_1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 typedef uint16_t touch_value_t; -#elif SOC_TOUCH_VERSION_2 // ESP32S2 ESP32S3 +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2 ESP32S3 typedef uint32_t touch_value_t; #endif @@ -71,7 +71,7 @@ void touchDetachInterrupt(uint8_t pin); * Default if Lower. **/ -#if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC +#if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC void touchInterruptSetThresholdDirection(bool mustbeLower); #endif @@ -83,7 +83,7 @@ void touchInterruptSetThresholdDirection(bool mustbeLower); * as soon as the touchpad is touched and/or released **/ -#if SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3 +#if SOC_TOUCH_SENSOR_VERSION == 2 // Only for ESP32S2 and ESP32S3 // returns true if touch pad has been and continues pressed and false otherwise bool touchInterruptGetLastStatus(uint8_t pin); #endif diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 7608502d0f8..e4432f5110f 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -61,10 +61,10 @@ struct uart_struct_t { static uart_t _uart_bus_array[] = { {0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 {1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, #endif }; @@ -81,10 +81,10 @@ static uart_t _uart_bus_array[] = { static uart_t _uart_bus_array[] = { {NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 {NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, #endif }; @@ -94,8 +94,8 @@ static uart_t _uart_bus_array[] = { // Negative Pin Number will keep it unmodified, thus this function can detach individual pins // This function will also unset the pins in the Peripheral Manager and set the pin to -1 after detaching static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { - if (uart_num >= SOC_UART_NUM) { - log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + if (uart_num >= SOC_UART_HP_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); return false; } // get UART information @@ -181,8 +181,8 @@ static bool _uartDetachBus_RTS(void *busptr) { // Attach function for UART // connects the IO Pad, set Paripheral Manager and internal UART structure data static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { - if (uart_num >= SOC_UART_NUM) { - log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + if (uart_num >= SOC_UART_HP_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); return false; } // get UART information @@ -308,8 +308,8 @@ bool uartIsDriverInstalled(uart_t *uart) { // Negative Pin Number will keep it unmodified, thus this function can set individual pins // When pins are changed, it will detach the previous one bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { - if (uart_num >= SOC_UART_NUM) { - log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + if (uart_num >= SOC_UART_HP_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); return false; } // get UART information @@ -378,7 +378,7 @@ bool _testUartBegin( uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint32_t rx_buffer_size, uint32_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd ) { - if (uart_nr >= SOC_UART_NUM) { + if (uart_nr >= SOC_UART_HP_NUM) { return false; // no new driver has to be installed } uart_t *uart = &_uart_bus_array[uart_nr]; @@ -400,8 +400,8 @@ uart_t *uartBegin( uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint32_t rx_buffer_size, uint32_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd ) { - if (uart_nr >= SOC_UART_NUM) { - log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + if (uart_nr >= SOC_UART_HP_NUM) { + log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); return NULL; // no new driver was installed } uart_t *uart = &_uart_bus_array[uart_nr]; @@ -604,8 +604,8 @@ bool uartSetRxFIFOFull(uart_t *uart, uint8_t numBytesFIFOFull) { } void uartEnd(uint8_t uart_num) { - if (uart_num >= SOC_UART_NUM) { - log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + if (uart_num >= SOC_UART_HP_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); return; } // get UART information @@ -819,14 +819,14 @@ static void ARDUINO_ISR_ATTR uart0_write_char(char c) { uart_ll_write_txfifo(&UART0, (const uint8_t *)&c, 1); } -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 static void ARDUINO_ISR_ATTR uart1_write_char(char c) { while (uart_ll_get_txfifo_len(&UART1) == 0); uart_ll_write_txfifo(&UART1, (const uint8_t *)&c, 1); } #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 static void ARDUINO_ISR_ATTR uart2_write_char(char c) { while (uart_ll_get_txfifo_len(&UART2) == 0); uart_ll_write_txfifo(&UART2, (const uint8_t *)&c, 1); @@ -836,10 +836,10 @@ static void ARDUINO_ISR_ATTR uart2_write_char(char c) { void uart_install_putc() { switch (s_uart_debug_nr) { case 0: ets_install_putc1((void (*)(char)) & uart0_write_char); break; -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 case 1: ets_install_putc1((void (*)(char)) & uart1_write_char); break; #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 case 2: ets_install_putc1((void (*)(char)) & uart2_write_char); break; #endif default: ets_install_putc1(NULL); break; @@ -850,7 +850,7 @@ void uart_install_putc() { // Routines that take care of UART mode in the HardwareSerial Class code // used to set UART_MODE_RS485_HALF_DUPLEX auto RTS for TXD for ESP32 chips bool uartSetMode(uart_t *uart, uart_mode_t mode) { - if (uart == NULL || uart->num >= SOC_UART_NUM) { + if (uart == NULL || uart->num >= SOC_UART_HP_NUM) { return false; } @@ -861,7 +861,7 @@ bool uartSetMode(uart_t *uart, uart_mode_t mode) { } void uartSetDebug(uart_t *uart) { - if (uart == NULL || uart->num >= SOC_UART_NUM) { + if (uart == NULL || uart->num >= SOC_UART_HP_NUM) { s_uart_debug_nr = -1; } else { s_uart_debug_nr = uart->num; @@ -1103,7 +1103,7 @@ unsigned long uartDetectBaudrate(uart_t *uart) { */ // gets the right TX or RX SIGNAL, based on the UART number from gpio_sig_map.h -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 #define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : (uartNumber == UART_NUM_1 ? U1TXD_OUT_IDX : U2TXD_OUT_IDX)) #define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : (uartNumber == UART_NUM_1 ? U1RXD_IN_IDX : U2RXD_IN_IDX)) #else @@ -1115,7 +1115,7 @@ unsigned long uartDetectBaudrate(uart_t *uart) { This creates a loop that lets us receive anything we send on the UART without external wires. */ void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) { - if (uartNum > SOC_UART_NUM - 1 || !GPIO_IS_VALID_GPIO(rxPin)) { + if (uartNum > SOC_UART_HP_NUM - 1 || !GPIO_IS_VALID_GPIO(rxPin)) { return; } esp_rom_gpio_connect_out_signal(rxPin, UART_TX_SIGNAL(uartNum), false, false); diff --git a/idf_component.yml b/idf_component.yml index 2f74301ea10..e6831d71b44 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -42,7 +42,7 @@ files: - "platform.txt" - "programmers.txt" dependencies: - idf: ">=5.1,<5.2" + idf: ">=5.3,<5.4" # mdns 1.2.1 is necessary to build H2 with no WiFi espressif/mdns: version: "^1.2.3" diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino index 343bd79c79b..d184a4ea769 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino @@ -17,12 +17,6 @@ #error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip. #endif -// Check Simple Secure Pairing -#if defined(CONFIG_BT_SSP_ENABLED) -#warning Legacy Pairing is disabled (CONFIG_BT_SSP_ENABLED is enabled. Disable it in menuconfig). -void setup() {} -void loop() {} -#else const char *deviceName = "ESP32_Legacy_example"; BluetoothSerial SerialBT; @@ -62,4 +56,3 @@ void loop() { delay(1); // Feed the watchdog } } -#endif diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino index eb0c05e0038..e5d05eed14e 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino @@ -22,11 +22,6 @@ #error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip. #endif -// Check Simple Secure Pairing -#if !defined(CONFIG_BT_SSP_ENABLED) -#error Simple Secure Pairing for Bluetooth is not available or not enabled. -#endif - const char *deviceName = "ESP32_SSP_example"; // The following lines defines the method of pairing diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/libraries/BluetoothSerial/src/BluetoothSerial.cpp index bcb94db910f..12c09d68305 100644 --- a/libraries/BluetoothSerial/src/BluetoothSerial.cpp +++ b/libraries/BluetoothSerial/src/BluetoothSerial.cpp @@ -71,11 +71,9 @@ static esp_bd_addr_t _peer_bd_addr; static char _remote_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1]; static bool _isRemoteAddressSet; static bool _isMaster; -#ifdef CONFIG_BT_SSP_ENABLED static bool _enableSSP; static bool _IO_CAP_INPUT; static bool _IO_CAP_OUTPUT; -#endif esp_bt_pin_code_t _pin_code = {0}; uint8_t _pin_code_len = 0; // Number of valid Bytes in the esp_bt_pin_code_t array static esp_spp_sec_t _sec_mask; @@ -538,7 +536,6 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa esp_bt_gap_pin_reply(param->pin_req.bda, true, _pin_code_len, _pin_code); } break; -#ifdef CONFIG_BT_SSP_ENABLED case ESP_BT_GAP_CFM_REQ_EVT: // Enum 6 - Security Simple Pairing User Confirmation request. log_i("ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val); if (confirm_request_callback) { @@ -549,13 +546,10 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, false); } break; -#endif case ESP_BT_GAP_KEY_NOTIF_EVT: // Enum 7 - Security Simple Pairing Passkey Notification log_i("ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey); break; - -#ifdef CONFIG_BT_SSP_ENABLED case ESP_BT_GAP_KEY_REQ_EVT: // Enum 8 - Security Simple Pairing Passkey request log_i("ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!"); if (key_request_callback) { @@ -566,7 +560,6 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, false); } break; -#endif case ESP_BT_GAP_READ_RSSI_DELTA_EVT: // Enum 9 - Read rssi event log_i("ESP_BT_GAP_READ_RSSI_DELTA_EVT Read rssi event"); @@ -707,7 +700,6 @@ static bool _init_bt(const char *deviceName, bt_mode mode) { log_i("device name set"); esp_bt_dev_set_device_name(deviceName); -#ifdef CONFIG_BT_SSP_ENABLED if (_enableSSP) { log_i("Simple Secure Pairing"); esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE; @@ -723,7 +715,6 @@ static bool _init_bt(const char *deviceName, bt_mode mode) { } esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t)); } -#endif // the default BTA_DM_COD_LOUDSPEAKER does not work with the macOS BT stack esp_bt_cod_t cod; @@ -894,7 +885,6 @@ void BluetoothSerial::memrelease() { esp_bt_mem_release(ESP_BT_MODE_BTDM); } -#ifdef CONFIG_BT_SSP_ENABLED void BluetoothSerial::onConfirmRequest(ConfirmRequestCb cb) { confirm_request_callback = cb; } @@ -906,7 +896,6 @@ void BluetoothSerial::onKeyRequest(KeyRequestCb cb) { void BluetoothSerial::respondPasskey(uint32_t passkey) { esp_bt_gap_ssp_passkey_reply(current_bd_addr, true, passkey); } -#endif void BluetoothSerial::onAuthComplete(AuthCompleteCb cb) { auth_complete_callback = cb; @@ -921,7 +910,6 @@ esp_err_t BluetoothSerial::register_callback(esp_spp_cb_t callback) { return ESP_OK; } -#ifdef CONFIG_BT_SSP_ENABLED // Enable Simple Secure Pairing (using generated PIN) // This must be called before calling begin, otherwise has no effect! void BluetoothSerial::enableSSP() { @@ -957,8 +945,6 @@ void BluetoothSerial::disableSSP() { _enableSSP = false; } -#else - bool BluetoothSerial::setPin(const char *pin, uint8_t pin_code_len) { if (pin_code_len == 0 || pin_code_len > 16) { log_e("PIN code must be 1-16 Bytes long! Called with length %d", pin_code_len); @@ -968,7 +954,6 @@ bool BluetoothSerial::setPin(const char *pin, uint8_t pin_code_len) { memcpy(_pin_code, pin, pin_code_len); return (esp_bt_gap_set_pin(ESP_BT_PIN_TYPE_FIXED, _pin_code_len, _pin_code) == ESP_OK); } -#endif bool BluetoothSerial::connect(String remoteName) { bool retval = false; diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.h b/libraries/BluetoothSerial/src/BluetoothSerial.h index 6b7ba419e00..d59fbf1f714 100644 --- a/libraries/BluetoothSerial/src/BluetoothSerial.h +++ b/libraries/BluetoothSerial/src/BluetoothSerial.h @@ -56,21 +56,16 @@ class BluetoothSerial : public Stream { void onData(BluetoothSerialDataCb cb); esp_err_t register_callback(esp_spp_cb_t callback); -#ifdef CONFIG_BT_SSP_ENABLED void onConfirmRequest(ConfirmRequestCb cb); void onKeyRequest(KeyRequestCb cb); void respondPasskey(uint32_t passkey); -#endif void onAuthComplete(AuthCompleteCb cb); void confirmReply(boolean confirm); -#ifdef CONFIG_BT_SSP_ENABLED void enableSSP(); void enableSSP(bool inputCapability, bool outputCapability); void disableSSP(); -#else bool setPin(const char *pin, uint8_t pin_code_len); -#endif bool connect(String remoteName); bool connect( uint8_t remoteAddress[], int channel = 0, esp_spp_sec_t sec_mask = (ESP_SPP_SEC_ENCRYPT | ESP_SPP_SEC_AUTHENTICATE), diff --git a/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino b/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino index eff21a1939e..3c5ff0ba6fc 100644 --- a/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino +++ b/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino @@ -11,7 +11,7 @@ */ // soc/soc_caps.h has information about each SoC target -// in this example, we use SOC_UART_NUM that goes from 1 to 3, +// in this example, we use SOC_UART_HP_NUM that goes from 1 to 3, // depending on the number of available UARTs in the ESP32xx // This makes the code transparent to what SoC is used. #include "soc/soc_caps.h" @@ -24,9 +24,9 @@ #define TXPIN 5 // GPIO 5 => TX for Serial1 or Serial2 // declare testingSerial (as reference) related to TEST_UART number defined above (only for Serial1 and Serial2) -#if SOC_UART_NUM > 1 && TEST_UART == 1 +#if SOC_UART_HP_NUM > 1 && TEST_UART == 1 HardwareSerial &testingSerial = Serial1; -#elif SOC_UART_NUM > 2 && TEST_UART == 2 +#elif SOC_UART_HP_NUM > 2 && TEST_UART == 2 HardwareSerial &testingSerial = Serial2; #endif @@ -36,11 +36,11 @@ void processOnReceiving(HardwareSerial &mySerial) { int8_t uart_num = -1; if (&mySerial == &Serial0) { uart_num = 0; -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 } else if (&mySerial == &Serial1) { uart_num = 1; #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 } else if (&mySerial == &Serial2) { uart_num = 2; #endif diff --git a/libraries/ESP_I2S/src/ESP_I2S.cpp b/libraries/ESP_I2S/src/ESP_I2S.cpp index 84050dfa6f8..50f76b41a3f 100644 --- a/libraries/ESP_I2S/src/ESP_I2S.cpp +++ b/libraries/ESP_I2S/src/ESP_I2S.cpp @@ -819,7 +819,7 @@ size_t I2SClass::readBytes(char *buffer, size_t size) { return total_size; } -size_t I2SClass::write(uint8_t *buffer, size_t size) { +size_t I2SClass::write(const uint8_t *buffer, size_t size) { size_t written = 0; size_t bytes_sent = 0; last_error = ESP_FAIL; diff --git a/libraries/ESP_I2S/src/ESP_I2S.h b/libraries/ESP_I2S/src/ESP_I2S.h index c83e3815ddb..60ccf0d4265 100644 --- a/libraries/ESP_I2S/src/ESP_I2S.h +++ b/libraries/ESP_I2S/src/ESP_I2S.h @@ -62,7 +62,7 @@ class I2SClass : public Stream { bool end(); size_t readBytes(char *buffer, size_t size); - size_t write(uint8_t *buffer, size_t size); + size_t write(const uint8_t *buffer, size_t size); i2s_chan_handle_t txChan(); uint32_t txSampleRate(); diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index 4d215d80034..48e8460fe2d 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -170,6 +170,11 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i Network.begin(); _ethernets[_eth_index] = this; +#if CONFIG_IDF_TARGET_ESP32 +#undef DEFAULT_RMII_CLK_GPIO +#define DEFAULT_RMII_CLK_GPIO (emac_rmii_clock_gpio_t)(CONFIG_ETH_RMII_CLK_IN_GPIO) +#endif + eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); mac_config.clock_config.rmii.clock_mode = (clock_mode) ? EMAC_CLK_OUT : EMAC_CLK_EXT_IN; mac_config.clock_config.rmii.clock_gpio = (1 == clock_mode) ? EMAC_APPL_CLK_OUT_GPIO diff --git a/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino b/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino index 2178c9bcd17..485da5b0bc2 100644 --- a/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino +++ b/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino @@ -36,7 +36,8 @@ static void smoke_test() { Insights.event(TAG, "[count][%d]", count); } else { log_e("[count][%d] [crash_count][%" PRIu32 "] [excvaddr][0x0f] Crashing...", count, s_reset_count); - *(int *)0x0F = 0x10; + //ToDo: find better way to crash + //*(int *)0x0F = 0x10; } } diff --git a/libraries/Network/src/NetworkClient.h b/libraries/Network/src/NetworkClient.h index 572292a7a99..7f37e0ff6e1 100644 --- a/libraries/Network/src/NetworkClient.h +++ b/libraries/Network/src/NetworkClient.h @@ -28,8 +28,6 @@ class NetworkClientRxBuffer; class ESPLwIPClient : public Client { public: - virtual int connect(IPAddress ip, uint16_t port, int32_t timeout) = 0; - virtual int connect(const char *host, uint16_t port, int32_t timeout) = 0; virtual void setConnectionTimeout(uint32_t milliseconds) = 0; }; diff --git a/libraries/PPP/src/PPP.cpp b/libraries/PPP/src/PPP.cpp index 8c25fe6aad5..bef283671da 100644 --- a/libraries/PPP/src/PPP.cpp +++ b/libraries/PPP/src/PPP.cpp @@ -279,7 +279,7 @@ bool PPPClass::begin(ppp_modem_model_t model, uint8_t uart_num, int baud_rate) { dte_config.uart_config.flow_control = _flow_ctrl; dte_config.uart_config.rx_buffer_size = _rx_buffer_size; dte_config.uart_config.tx_buffer_size = _tx_buffer_size; - dte_config.uart_config.port_num = _uart_num; + dte_config.uart_config.port_num = (uart_port_t)_uart_num; dte_config.uart_config.baud_rate = baud_rate; /* Configure the DCE */ diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 9f612b34646..8c585fa86ed 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -42,42 +42,32 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.1-c608177cf9" + "version": "idf-release_v5.3-466a392a" }, { "packager": "esp32", - "name": "xtensa-esp32-elf-gcc", - "version": "esp-12.2.0_20230208" - }, - { - "packager": "esp32", - "name": "xtensa-esp32s2-elf-gcc", - "version": "esp-12.2.0_20230208" - }, - { - "packager": "esp32", - "name": "xtensa-esp32s3-elf-gcc", - "version": "esp-12.2.0_20230208" + "name": "xtensa-esp-elf-gcc", + "version": "esp-13.2.0_20240530" }, { "packager": "esp32", "name": "xtensa-esp-elf-gdb", - "version": "12.1_20231023" + "version": "14.2_20240403" }, { "packager": "esp32", "name": "riscv32-esp-elf-gcc", - "version": "esp-12.2.0_20230208" + "version": "esp-13.2.0_20240530" }, { "packager": "esp32", "name": "riscv32-esp-elf-gdb", - "version": "12.1_20231023" + "version": "14.2_20240403" }, { "packager": "esp32", "name": "openocd-esp32", - "version": "v0.12.0-esp32-20240726" + "version": "v0.12.0-esp32-20240318" }, { "packager": "esp32", @@ -105,490 +95,366 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.1-c608177cf9", + "version": "idf-release_v5.3-466a392a", "systems": [ { "host": "i686-mingw32", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/7b015a59844d511b72663a266e5793fb98eecaa1", - "archiveFileName": "esp32-arduino-libs-7b015a59844d511b72663a266e5793fb98eecaa1.zip", - "checksum": "SHA-256:392c411dc6b8253a3d067fda6c41a3f67ade2f99259a1a707630568e8f80f055", - "size": "310235817" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", + "size": "318864212" }, { "host": "x86_64-mingw32", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/7b015a59844d511b72663a266e5793fb98eecaa1", - "archiveFileName": "esp32-arduino-libs-7b015a59844d511b72663a266e5793fb98eecaa1.zip", - "checksum": "SHA-256:392c411dc6b8253a3d067fda6c41a3f67ade2f99259a1a707630568e8f80f055", - "size": "310235817" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", + "size": "318864212" }, { "host": "arm64-apple-darwin", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/7b015a59844d511b72663a266e5793fb98eecaa1", - "archiveFileName": "esp32-arduino-libs-7b015a59844d511b72663a266e5793fb98eecaa1.zip", - "checksum": "SHA-256:392c411dc6b8253a3d067fda6c41a3f67ade2f99259a1a707630568e8f80f055", - "size": "310235817" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", + "size": "318864212" }, { "host": "x86_64-apple-darwin", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/7b015a59844d511b72663a266e5793fb98eecaa1", - "archiveFileName": "esp32-arduino-libs-7b015a59844d511b72663a266e5793fb98eecaa1.zip", - "checksum": "SHA-256:392c411dc6b8253a3d067fda6c41a3f67ade2f99259a1a707630568e8f80f055", - "size": "310235817" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", + "size": "318864212" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/7b015a59844d511b72663a266e5793fb98eecaa1", - "archiveFileName": "esp32-arduino-libs-7b015a59844d511b72663a266e5793fb98eecaa1.zip", - "checksum": "SHA-256:392c411dc6b8253a3d067fda6c41a3f67ade2f99259a1a707630568e8f80f055", - "size": "310235817" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", + "size": "318864212" }, { "host": "i686-pc-linux-gnu", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/7b015a59844d511b72663a266e5793fb98eecaa1", - "archiveFileName": "esp32-arduino-libs-7b015a59844d511b72663a266e5793fb98eecaa1.zip", - "checksum": "SHA-256:392c411dc6b8253a3d067fda6c41a3f67ade2f99259a1a707630568e8f80f055", - "size": "310235817" - }, - { - "host": "aarch64-linux-gnu", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/7b015a59844d511b72663a266e5793fb98eecaa1", - "archiveFileName": "esp32-arduino-libs-7b015a59844d511b72663a266e5793fb98eecaa1.zip", - "checksum": "SHA-256:392c411dc6b8253a3d067fda6c41a3f67ade2f99259a1a707630568e8f80f055", - "size": "310235817" - }, - { - "host": "arm-linux-gnueabihf", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/7b015a59844d511b72663a266e5793fb98eecaa1", - "archiveFileName": "esp32-arduino-libs-7b015a59844d511b72663a266e5793fb98eecaa1.zip", - "checksum": "SHA-256:392c411dc6b8253a3d067fda6c41a3f67ade2f99259a1a707630568e8f80f055", - "size": "310235817" - } - ] - }, - { - "name": "xtensa-esp32-elf-gcc", - "version": "esp-12.2.0_20230208", - "systems": [ - { - "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz", - "checksum": "SHA-256:e8d35938385447cf9c34735fee2a3b2b61cca6be07db77a45856a1c2a347e423", - "size": "111766903" - }, - { - "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz", - "checksum": "SHA-256:569988acfc2673369f222037c64bac96990cee08cebeebc4f8860e0d984f8bd9", - "size": "106473247" - }, - { - "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz", - "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz", - "checksum": "SHA-256:6a844f16021e936cc9b87b203978356f57ab2144554f6f2a0f73ffa3d3d316c5", - "size": "105576049" - }, - { - "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-i686-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-i686-linux-gnu.tar.gz", - "checksum": "SHA-256:743d6f03a89329bb09f9550d27fcab677f5cf06b4720793bbcef7883a932681d", - "size": "114870843" - }, - { - "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz", - "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz", - "checksum": "SHA-256:4d32d764e984f3a570aacfb2f4957619540fb4629534d969b2e83997901334c3", - "size": "119424029" - }, - { - "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz", - "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz", - "checksum": "SHA-256:dc8fa7f4933bf5cb08e83bacce6160cc9dfe93d7aad1e8f92599bb81ff5b2e28", - "size": "106136827" - }, - { - "host": "i686-mingw32", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-i686-w64-mingw32.zip", - "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-i686-w64-mingw32.zip", - "checksum": "SHA-256:62bb6428d107ed3f44c212c77ecf24804b74c97327b0f0ad2029c656c6dbd6ee", - "size": "130847086" - }, - { - "host": "x86_64-mingw32", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-x86_64-w64-mingw32.zip", - "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-x86_64-w64-mingw32.zip", - "checksum": "SHA-256:8febfe4a6476efc69012390106c8c660a14418f025137b0513670c72124339cf", - "size": "134985117" - } - ] - }, - { - "name": "xtensa-esp32s2-elf-gcc", - "version": "esp-12.2.0_20230208", - "systems": [ - { - "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz", - "checksum": "SHA-256:2ff838520a5003d2768b275f5bb5ead69dd2388c3b7cd9043cb59891ba43147f", - "size": "112199211" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", + "size": "318864212" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz", - "checksum": "SHA-256:6d79d5b14fc7129a9b8208d54e19b05dedb565f50f7a96264c9df84b06ad3be0", - "size": "106953064" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", + "size": "318864212" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz", - "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz", - "checksum": "SHA-256:e5bd03b6ad19179b015a93ada9992adc3610036ebf6aeb0835a09c9aadb50a14", - "size": "106026829" - }, - { - "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-i686-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-i686-linux-gnu.tar.gz", - "checksum": "SHA-256:fb45943557b2d201bbb1bdc7514a1872f9bb96c2dfb48b95abdba281cc792f75", - "size": "115288662" - }, - { - "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz", - "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz", - "checksum": "SHA-256:e965236cb80e45282d16f40184af183e013b63b177bd1884736c463eac636564", - "size": "119711811" - }, - { - "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz", - "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz", - "checksum": "SHA-256:78a55eec18650b21378d97494989ffe208748e0f49bb2b2d6756b264e1863919", - "size": "106540817" - }, - { - "host": "i686-mingw32", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-i686-w64-mingw32.zip", - "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-i686-w64-mingw32.zip", - "checksum": "SHA-256:1e6dac5162ab75f94b88c47ebeabb6600c652fb4f615ed07c1724d037c02fd19", - "size": "131273859" - }, - { - "host": "x86_64-mingw32", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-x86_64-w64-mingw32.zip", - "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-x86_64-w64-mingw32.zip", - "checksum": "SHA-256:8a785cc4e0838cebe404f82c0ead7a0f9ac5fabc660a742e33a41ddac6326cc1", - "size": "135373049" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", + "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", + "size": "318864212" } ] }, { - "name": "xtensa-esp32s3-elf-gcc", - "version": "esp-12.2.0_20230208", + "name": "xtensa-esp-elf-gcc", + "version": "esp-13.2.0_20240530", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz", - "checksum": "SHA-256:61495ffe575e00c6998ae7274ff917658c04bded62ece0937c7042d6dcbf46de", - "size": "111971129" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.gz", + "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.gz", + "checksum": "SHA-256:bce77e8480701d5a90545369d1b5848f6048eb39c0022d2446d1e33a8e127490", + "size": "208911713" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz", - "checksum": "SHA-256:9008d395be46fcfe68c7de6edc850fc1595f28323a28e7922e5c085bd310cb90", - "size": "106616800" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.gz", + "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.gz", + "checksum": "SHA-256:7c9e3c1adc733d042ed87b92daa1d6396e1b441c1755f1fa14cb88855719ba88", + "size": "202519931" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz", - "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz", - "checksum": "SHA-256:568857bdac7dea389dffc7fbc6871b4af299150a8ecf1bf965f224d2a1655edb", - "size": "105700326" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.gz", + "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.gz", + "checksum": "SHA-256:d6955e8ea6af91574bf9213b92f32ca09eb8640103446b7fa19a63cfeeec5421", + "size": "202206516" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-i686-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-i686-linux-gnu.tar.gz", - "checksum": "SHA-256:d122738bcc6c2f52d05fa89b2fb1afe6a7894cda8a07a1879aca867a31507ed0", - "size": "115098400" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.gz", + "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.gz", + "checksum": "SHA-256:3666ee74ecb693ee6488f11469802630a7b0d32608184045a4f35cb413f59e3d", + "size": "213304863" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz", - "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz", - "checksum": "SHA-256:7defcddb98788b0991416ad2e0cb6a3b248b8030f22d5d76b8832117cc1494ca", - "size": "119883189" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.gz", + "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.gz", + "checksum": "SHA-256:948cf57b6eecc898b5f70e06ad08ba88c08b627be570ec631dfcd72f6295194a", + "size": "221357024" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz", - "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz", - "checksum": "SHA-256:b59e076f8e4b9ca99535d449f9fc4cbb443188051dce4ad934e38f16b095f8d9", - "size": "106464677" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.gz", + "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.gz", + "checksum": "SHA-256:6f03fdf0cc14a7f3900ee59977f62e8626d8b7c208506e52f1fd883ac223427a", + "size": "199689745" }, { "host": "i686-mingw32", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-i686-w64-mingw32.zip", - "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-i686-w64-mingw32.zip", - "checksum": "SHA-256:3ddf51774817e815e5d41c312a90c1159226978fb45fd0d4f7085c567f8b73ab", - "size": "131134034" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-i686-w64-mingw32_hotfix.zip", + "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-i686-w64-mingw32_hotfix.zip", + "checksum": "SHA-256:d6b227c50e3c8e21d62502b3140e5ab74a4cb502c2b4169c36238b9858a8fb88", + "size": "266042967" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-x86_64-w64-mingw32.zip", - "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-x86_64-w64-mingw32.zip", - "checksum": "SHA-256:1d15ca65e3508388a86d8bed3048c46d07538f5bc88d3e4296f9c03152087cd1", - "size": "135381926" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-w64-mingw32_hotfix.zip", + "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-x86_64-w64-mingw32_hotfix.zip", + "checksum": "SHA-256:155ee97b531236e6a7c763395c68ca793e55e74d2cb4d38a23057a153e01e7d0", + "size": "269831985" } ] }, { "name": "xtensa-esp-elf-gdb", - "version": "12.1_20231023", + "version": "14.2_20240403", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-x86_64-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-x86_64-linux-gnu.tar.gz", - "checksum": "SHA-256:d0743ec43cd92c35452a9097f7863281de4e72f04120d63cfbcf9d591a373529", - "size": "36942094" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-x86_64-linux-gnu.tar.gz", + "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-x86_64-linux-gnu.tar.gz", + "checksum": "SHA-256:9d68472d4cba5cf8c2b79d94f86f92c828e76a632bd1e6be5e7706e5b304d36e", + "size": "31010320" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-aarch64-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-aarch64-linux-gnu.tar.gz", - "checksum": "SHA-256:bc1fac0366c6a08e26c45896ca21c8c90efc2cdd431b8ba084e8772e15502d0e", - "size": "37134601" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-aarch64-linux-gnu.tar.gz", + "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-aarch64-linux-gnu.tar.gz", + "checksum": "SHA-256:bdabc3217994815fc311c4e16e588b78f6596b5ad4ffa46c80b40e982cfb1e66", + "size": "30954580" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-arm-linux-gnueabi.tar.gz", - "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-arm-linux-gnueabi.tar.gz", - "checksum": "SHA-256:25efc51d52b71f097ccec763c5c885c8f5026b432fec4b5badd6a5f36fe34d04", - "size": "34579556" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-arm-linux-gnueabi.tar.gz", + "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-arm-linux-gnueabi.tar.gz", + "checksum": "SHA-256:d54b8d703ba897b28c627da3d27106a3906dd01ba298778a67064710bc33c76d", + "size": "28697281" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-i586-linux-gnu.tar.gz", - "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-i586-linux-gnu.tar.gz", - "checksum": "SHA-256:e0af0b3b4a6b29a843cd5f47e331a966d9258f7d825b4656c6251490f71b05b2", - "size": "35676578" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-i586-linux-gnu.tar.gz", + "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-i586-linux-gnu.tar.gz", + "checksum": "SHA-256:64d3bc992ed8fdec383d49e8b803ac494605a38117c8293db8da055037de96b0", + "size": "29890994" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-x86_64-apple-darwin14.tar.gz", - "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-x86_64-apple-darwin14.tar.gz", - "checksum": "SHA-256:bd146fd99a52b2d71c7ce0f62b9e18f3423d6cae7b2b2c954046b0dd7a23142f", - "size": "52863941" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-x86_64-apple-darwin14.tar.gz", + "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-x86_64-apple-darwin14.tar.gz", + "checksum": "SHA-256:023e74b3fda793da4bc0509b02de776ee0dad6efaaac17bef5916fb7dc9c26b9", + "size": "44446611" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-aarch64-apple-darwin21.1.tar.gz", - "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-aarch64-apple-darwin21.1.tar.gz", - "checksum": "SHA-256:5edc76565bf9d2fadf24e443ddf3df7567354f336a65d4af5b2ee805cdfcec24", - "size": "33504923" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-aarch64-apple-darwin21.1.tar.gz", + "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-aarch64-apple-darwin21.1.tar.gz", + "checksum": "SHA-256:ea757c6bf8c25238f6d2fdcc6bbab25a1b00608a0f9e19b7ddd2f37ddbdc3fb1", + "size": "37021423" }, { "host": "i686-mingw32", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-i686-w64-mingw32.zip", - "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-i686-w64-mingw32.zip", - "checksum": "SHA-256:ea4f3ee6b95ad1ad2e07108a21a50037a3e64a420cdeb34b2ba95d612faed898", - "size": "31068749" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-i686-w64-mingw32.zip", + "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-i686-w64-mingw32.zip", + "checksum": "SHA-256:322e8d9b700dc32d8158e3dc55fb85ec55de48d0bb7789375ee39a28d5d655e2", + "size": "26302466" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-x86_64-w64-mingw32.zip", - "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-x86_64-w64-mingw32.zip", - "checksum": "SHA-256:13bb97f39173948d1cfb6e651d9b335ea9d52f1fdd0dda1eda3a2d23d8c63644", - "size": "33514906" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-x86_64-w64-mingw32.zip", + "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-x86_64-w64-mingw32.zip", + "checksum": "SHA-256:a27a2fe20f192f8e0a51b8936428b4e1cf8935cfe008ee445cc49f6fc7f6db2e", + "size": "28366035" } ] }, { "name": "riscv32-esp-elf-gcc", - "version": "esp-12.2.0_20230208", + "version": "esp-13.2.0_20240530", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz", - "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz", - "checksum": "SHA-256:1eb0d65990547ee9706b90406600cbc3638814d5feb7c1f7b44bb5416478a5bd", - "size": "257615266" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.gz", + "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.gz", + "checksum": "SHA-256:e7fbfffbb19dcd3764a9848a141bf44e19ad0b48e0bd1515912345c26fe52fba", + "size": "294346758" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz", - "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz", - "checksum": "SHA-256:921fcdc170c7fe5d6a0a30470ed1875c8926d910c19739fc950c8d1836e4c1c5", - "size": "253094184" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.gz", + "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.gz", + "checksum": "SHA-256:a178a895b807ed2e87d5d62153c36a6aae048581f527c0eb152f0a02b8de9571", + "size": "288374597" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz", - "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz", - "checksum": "SHA-256:f66e06312b58251c2121c1b1df1102565708573b86b2a9fe0c03ea1b0e9a7511", - "size": "252558021" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.gz", + "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.gz", + "checksum": "SHA-256:4a2f176d0f5bc8a70645975e2a08ea94145fb69b7225c5cdcbd6024a4836aaf5", + "size": "287737495" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-i686-linux-gnu.tar.gz", - "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-i686-linux-gnu.tar.gz", - "checksum": "SHA-256:8abcac0331ef8973d1c705e77523364ebec7e98b37640d4a1d036912f3cbe946", - "size": "261248375" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.gz", + "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.gz", + "checksum": "SHA-256:7a6f02f1b2effafb18600bbf602818f6923fd320f000fb8659f34acbfda8812f", + "size": "299138540" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz", - "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz", - "checksum": "SHA-256:76a334bc75a4e3891c222c84d7968817f2d0699d2976fc2a1658e56395283bec", - "size": "268987133" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.gz", + "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.gz", + "checksum": "SHA-256:a193b4f025d0d836b0a9d9cbe760af1c53e53af66fc332fe98952bc4c456dd9a", + "size": "305025700" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz", - "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz", - "checksum": "SHA-256:f30571945b257a10a26901bba3c5892e07c192aacf9ed6e8fcd11ca36ed827d2", - "size": "252159713" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.gz", + "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.gz", + "checksum": "SHA-256:7082dd2e2123dea5609a24092d19ac6612ae7e219df1d298de6b2f64cb4af0df", + "size": "285458443" }, { "host": "i686-mingw32", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-i686-w64-mingw32.zip", - "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-i686-w64-mingw32.zip", - "checksum": "SHA-256:a5dfbb6dbf6fc6c6ea9beb2723af059ba3c5b2c86c2f0dc3b21afdc7bb229bf5", - "size": "324863847" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-i686-w64-mingw32.zip", + "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-i686-w64-mingw32.zip", + "checksum": "SHA-256:590bfb10576702639825581cc00c445da6e577012840a787137417e80d15f46d", + "size": "366573064" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-x86_64-w64-mingw32.zip", - "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-x86_64-w64-mingw32.zip", - "checksum": "SHA-256:9deae9e0013b2f7bbf017f9c8135755bfa89522f337c7dca35872bf12ec08176", - "size": "328092732" + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-w64-mingw32.zip", + "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-x86_64-w64-mingw32.zip", + "checksum": "SHA-256:413eb9f6adf8fdaf25544d014c850fc09eb38bb93a2fc5ebd107ab1b0de1bb3a", + "size": "369820297" } ] }, { "name": "riscv32-esp-elf-gdb", - "version": "12.1_20231023", + "version": "14.2_20240403", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-x86_64-linux-gnu.tar.gz", - "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-x86_64-linux-gnu.tar.gz", - "checksum": "SHA-256:2c78b806be176b1e449e07ff83429d38dfc39a13f89a127ac1ffa6c1230537a0", - "size": "36630145" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-x86_64-linux-gnu.tar.gz", + "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-x86_64-linux-gnu.tar.gz", + "checksum": "SHA-256:ce004bc0bbd71b246800d2d13b239218b272a38bd528e316f21f1af2db8a4b13", + "size": "30707431" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-aarch64-linux-gnu.tar.gz", - "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-aarch64-linux-gnu.tar.gz", - "checksum": "SHA-256:33f80117c8777aaff9179e27953e41764c5c46b3c576dc96a37ecc7a368807ec", - "size": "36980143" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-aarch64-linux-gnu.tar.gz", + "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-aarch64-linux-gnu.tar.gz", + "checksum": "SHA-256:ba10f2866c61410b88c65957274280b1a62e3bed05131654ed9b6758efe18e55", + "size": "30824065" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-arm-linux-gnueabi.tar.gz", - "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-arm-linux-gnueabi.tar.gz", - "checksum": "SHA-256:292e6ec0a9381c1480bbadf5caae25e86428b68fb5d030c9be7deda5e7f070e0", - "size": "34950318" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-arm-linux-gnueabi.tar.gz", + "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-arm-linux-gnueabi.tar.gz", + "checksum": "SHA-256:88539db5d987f28827efac7e26080a2803b9b539342ccd2963ccfdd56d7f08f7", + "size": "29000575" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-i586-linux-gnu.tar.gz", - "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-i586-linux-gnu.tar.gz", - "checksum": "SHA-256:68a25fbcfc6371ec4dbe503ec92211977eb2006f0c29e67dbce6b93c70c6b7ec", - "size": "35801607" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-i586-linux-gnu.tar.gz", + "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-i586-linux-gnu.tar.gz", + "checksum": "SHA-256:0e628ee37438ab6ba05eb889a76d09e50cb98e0020a16b8e2b935c5cf19b4ed2", + "size": "29947521" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-x86_64-apple-darwin14.tar.gz", - "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-x86_64-apple-darwin14.tar.gz", - "checksum": "SHA-256:322c722e6c12225ed8cd97f95a0375105756dc5113d369958ce0858ad1a90257", - "size": "52618688" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-x86_64-apple-darwin14.tar.gz", + "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-x86_64-apple-darwin14.tar.gz", + "checksum": "SHA-256:8f6bda832d70dad5860a639d55aba4237bd10cbac9f4822db1eece97357b34a9", + "size": "44196117" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-aarch64-apple-darwin21.1.tar.gz", - "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-aarch64-apple-darwin21.1.tar.gz", - "checksum": "SHA-256:c2224b3a8d02451c530cf004c29653292d963a1b4021b4b472b862b6dbe97e0b", - "size": "33149392" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-aarch64-apple-darwin21.1.tar.gz", + "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-aarch64-apple-darwin21.1.tar.gz", + "checksum": "SHA-256:d88b6116e86456c8480ce9bc95aed375a35c0d091f1da0a53b86be0e6ef3d320", + "size": "36794404" }, { "host": "i686-mingw32", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-i686-w64-mingw32.zip", - "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-i686-w64-mingw32.zip", - "checksum": "SHA-256:4b42149a99dd87ee7e6dde25c99bad966c7f964253fa8f771593d7cef69f5602", - "size": "31635103" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-i686-w64-mingw32.zip", + "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-i686-w64-mingw32.zip", + "checksum": "SHA-256:d6e7ce05805b0d8d4dd138ad239b98a1adf8da98941867d60760eb1ae5361730", + "size": "26486295" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-x86_64-w64-mingw32.zip", - "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-x86_64-w64-mingw32.zip", - "checksum": "SHA-256:728231546ad5006d34463f972658b2a89e52f660a42abab08a29bedd4a8046ad", - "size": "33400816" + "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-x86_64-w64-mingw32.zip", + "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-x86_64-w64-mingw32.zip", + "checksum": "SHA-256:5c9f211dc46daf6b96fad09d709284a0f0186fef8947d9f6edd6bca5b5ad4317", + "size": "27942579" } ] }, { "name": "openocd-esp32", - "version": "v0.12.0-esp32-20240726", + "version": "v0.12.0-esp32-20240318", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240726/openocd-esp32-linux-amd64-0.12.0-esp32-20240726.tar.gz", - "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20240726.tar.gz", - "checksum": "SHA-256:31fabbda5f39262ea4ed8cbba8adedc1d39838f01043cfab95435743c126ac56", - "size": "2368175" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-linux-amd64-0.12.0-esp32-20240318.tar.gz", + "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20240318.tar.gz", + "checksum": "SHA-256:cf26c5cef4f6b04aa23cd2778675604e5a74a4ce4d8d17b854d05fbcb782d52c", + "size": "2252682" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240726/openocd-esp32-linux-arm64-0.12.0-esp32-20240726.tar.gz", - "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20240726.tar.gz", - "checksum": "SHA-256:05589effadc93440ecca4a8ecc64e78dc94185a4ab72bc54634751dd7b6060d0", - "size": "2239793" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-linux-arm64-0.12.0-esp32-20240318.tar.gz", + "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20240318.tar.gz", + "checksum": "SHA-256:9b97a37aa2cab94424a778c25c0b4aa0f90d6ef9cda764a1d9289d061305f4b7", + "size": "2132904" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240726/openocd-esp32-linux-armel-0.12.0-esp32-20240726.tar.gz", - "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20240726.tar.gz", - "checksum": "SHA-256:25d241fd7467cc5aa8ec3256f2efca27d86bde7cf5577c32f742ad1cc598ad7d", - "size": "2388355" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-linux-armel-0.12.0-esp32-20240318.tar.gz", + "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20240318.tar.gz", + "checksum": "SHA-256:b7e82776ec374983807d3389df09c632ad9bc8341f2075690b6b500319dfeaf4", + "size": "2271761" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240726/openocd-esp32-macos-0.12.0-esp32-20240726.tar.gz", - "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20240726.tar.gz", - "checksum": "SHA-256:c3fb8209dd046f83e9fe98b054649020991aea0ac95cf175a41967d446330148", - "size": "2478569" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-macos-0.12.0-esp32-20240318.tar.gz", + "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20240318.tar.gz", + "checksum": "SHA-256:b16c3082c94df1079367c44d99f7a8605534cd48aabc18898e46e94a2c8c57e7", + "size": "2365588" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240726/openocd-esp32-macos-arm64-0.12.0-esp32-20240726.tar.gz", - "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20240726.tar.gz", - "checksum": "SHA-256:45b317f233ae7bf3059a93db925d8794affd393b170ef496da08fa3f2b360ac7", - "size": "2522358" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-macos-arm64-0.12.0-esp32-20240318.tar.gz", + "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20240318.tar.gz", + "checksum": "SHA-256:534ec925ae6e35e869e4e4e6e4d2c4a1eb081f97ebcc2dd5efdc52d12f4c2f86", + "size": "2406377" }, { "host": "i686-mingw32", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240726/openocd-esp32-win32-0.12.0-esp32-20240726.zip", - "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20240726.zip", - "checksum": "SHA-256:9735c9ada83bab1ff2b306f06b96421572fa12d01a751e09e10f243222fd95c4", - "size": "2907592" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-win32-0.12.0-esp32-20240318.zip", + "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20240318.zip", + "checksum": "SHA-256:d379329eba052435173ab0d69c9b15bc164a6ce489e2a67cd11169d2dabff633", + "size": "2783915" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240726/openocd-esp32-win64-0.12.0-esp32-20240726.zip", - "archiveFileName": "openocd-esp32-win64-0.12.0-esp32-20240726.zip", - "checksum": "SHA-256:139d5ae128ea12023793e8bccdde7dd14383ad38c265cf66c9c6cc7c804e1333", - "size": "2907591" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-win32-0.12.0-esp32-20240318.zip", + "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20240318.zip", + "checksum": "SHA-256:d379329eba052435173ab0d69c9b15bc164a6ce489e2a67cd11169d2dabff633", + "size": "2783915" } ] }, diff --git a/platform.txt b/platform.txt index f3eb69f0862..57609e5dda3 100644 --- a/platform.txt +++ b/platform.txt @@ -3,9 +3,7 @@ version=3.0.4 tools.esp32-arduino-libs.path={runtime.platform.path}/tools/esp32-arduino-libs tools.esp32-arduino-libs.path.windows={runtime.platform.path}\tools\esp32-arduino-libs -tools.xtensa-esp32-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp32-elf -tools.xtensa-esp32s2-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp32s2-elf -tools.xtensa-esp32s3-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp32s3-elf +tools.xtensa-esp-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp-elf tools.xtensa-esp-elf-gdb.path={runtime.platform.path}/tools/xtensa-esp-elf-gdb tools.riscv32-esp-elf-gcc.path={runtime.platform.path}/tools/riscv32-esp-elf tools.riscv32-esp-elf-gdb.path={runtime.platform.path}/tools/riscv32-esp-elf-gdb @@ -27,7 +25,7 @@ tools.gen_esp32part.cmd.windows="{runtime.platform.path}\tools\gen_esp32part.exe tools.gen_insights_pkg.cmd=python3 "{runtime.platform.path}"/tools/gen_insights_package.py tools.gen_insights_pkg.cmd.windows="{runtime.platform.path}\tools\gen_insights_package.exe" -compiler.path={tools.{build.tarch}-{build.target}-elf-gcc.path}/bin/ +compiler.path={tools.{build.tarch}-esp-elf-gcc.path}/bin/ compiler.prefix={build.tarch}-{build.target}-elf- compiler.sdk.path={tools.esp32-arduino-libs.path}/{build.mcu} diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 527d28241d9..a68ef879659 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -46,7 +46,7 @@ * */ -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 // Used for the pin swap test #define NEW_RX1 9 #define NEW_TX1 10 @@ -64,14 +64,14 @@ extern int8_t uart_get_TxPin(uint8_t uart_num); // This function starts all the available test UARTs void start_serial(unsigned long baudrate = 115200) { -#if SOC_UART_NUM >= 2 +#if SOC_UART_HP_NUM >= 2 Serial1.begin(baudrate); while (!Serial1) { delay(10); } #endif -#if SOC_UART_NUM >= 3 +#if SOC_UART_HP_NUM >= 3 Serial2.begin(baudrate); while (!Serial2) { delay(10); @@ -81,11 +81,11 @@ void start_serial(unsigned long baudrate = 115200) { // This function stops all the available test UARTs void stop_serial(bool hard_stop = false) { -#if SOC_UART_NUM >= 2 +#if SOC_UART_HP_NUM >= 2 Serial1.end(/*hard_stop*/); #endif -#if SOC_UART_NUM >= 3 +#if SOC_UART_HP_NUM >= 3 Serial2.end(/*hard_stop*/); #endif } @@ -93,14 +93,14 @@ void stop_serial(bool hard_stop = false) { // This function transmits a message and checks if it was received correctly void transmit_and_check_msg(const String msg_append, bool perform_assert = true) { delay(100); // Wait for some settings changes to take effect -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 Serial1.print("Hello from Serial1 (UART1) >>> via loopback >>> Serial1 (UART1) " + msg_append); Serial1.flush(); delay(100); if (perform_assert) { TEST_ASSERT_EQUAL_STRING(("Hello from Serial1 (UART1) >>> via loopback >>> Serial1 (UART1) " + msg_append).c_str(), recv_msg.c_str()); } -#elif SOC_UART_NUM == 3 +#elif SOC_UART_HP_NUM == 3 Serial1.print("Hello from Serial1 (UART1) >>> to >>> Serial2 (UART2) " + msg_append); Serial1.flush(); delay(100); @@ -126,9 +126,9 @@ void transmit_and_check_msg(const String msg_append, bool perform_assert = true) void task_delayed_msg(void *pvParameters) { HardwareSerial *selected_serial; -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 selected_serial = &Serial; -#elif SOC_UART_NUM == 3 +#elif SOC_UART_HP_NUM == 3 selected_serial = &Serial1; #endif @@ -143,14 +143,14 @@ void task_delayed_msg(void *pvParameters) { // This function is automatically called by unity before each test is run void setUp(void) { start_serial(115200); -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 log_d("Setup internal loop-back from and back to Serial1 (UART1) TX >> Serial1 (UART1) RX"); Serial1.onReceive([]() { onReceive_cb(Serial1); }); uart_internal_loopback(1, RX1); -#elif SOC_UART_NUM == 3 +#elif SOC_UART_HP_NUM == 3 log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)"); Serial1.onReceive([]() { @@ -180,11 +180,11 @@ void onReceive_cb(HardwareSerial &selected_serial) { if (&selected_serial == &Serial) { uart_num = 0; -#if SOC_UART_NUM >= 2 +#if SOC_UART_HP_NUM >= 2 } else if (&selected_serial == &Serial1) { uart_num = 1; #endif -#if SOC_UART_NUM >= 3 +#if SOC_UART_HP_NUM >= 3 } else if (&selected_serial == &Serial2) { uart_num = 2; #endif @@ -225,7 +225,7 @@ void change_baudrate_test(void) { Serial1.updateBaudRate(9600); TEST_ASSERT_UINT_WITHIN(192, 9600, Serial1.baudRate()); -#if SOC_UART_NUM == 3 +#if SOC_UART_HP_NUM == 3 Serial2.updateBaudRate(9600); TEST_ASSERT_UINT_WITHIN(192, 9600, Serial2.baudRate()); #endif @@ -239,7 +239,7 @@ void change_baudrate_test(void) { //Baudrate error should be within 2% of the target baudrate TEST_ASSERT_UINT_WITHIN(2304, 115200, Serial1.baudRate()); -#if SOC_UART_NUM == 3 +#if SOC_UART_HP_NUM == 3 TEST_ASSERT_UINT_WITHIN(2304, 115200, Serial2.baudRate()); #endif @@ -419,20 +419,20 @@ void change_pins_test(void) { log_d("Disabling UART loopback"); -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 esp_rom_gpio_connect_out_signal(SOC_RX0, SIG_GPIO_OUT_IDX, false, false); -#elif SOC_UART_NUM == 3 +#elif SOC_UART_HP_NUM == 3 esp_rom_gpio_connect_out_signal(RX1, SIG_GPIO_OUT_IDX, false, false); esp_rom_gpio_connect_out_signal(RX2, SIG_GPIO_OUT_IDX, false, false); #endif log_d("Swapping UART pins"); -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 Serial1.setPins(NEW_RX1, NEW_TX1); TEST_ASSERT_EQUAL(NEW_RX1, uart_get_RxPin(1)); TEST_ASSERT_EQUAL(NEW_TX1, uart_get_TxPin(1)); -#elif SOC_UART_NUM == 3 +#elif SOC_UART_HP_NUM == 3 Serial1.setPins(RX2, TX2); Serial2.setPins(RX1, TX1); TEST_ASSERT_EQUAL(RX2, uart_get_RxPin(1)); @@ -445,9 +445,9 @@ void change_pins_test(void) { log_d("Re-enabling UART loopback"); -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 uart_internal_loopback(1, NEW_RX1); -#elif SOC_UART_NUM == 3 +#elif SOC_UART_HP_NUM == 3 uart_internal_loopback(1, RX1); uart_internal_loopback(2, RX2); #endif @@ -467,10 +467,10 @@ void auto_baudrate_test(void) { log_d("Stopping test serial. Using Serial2 for ESP32 and Serial1 for ESP32-S2."); -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 selected_serial = &Serial1; uart_internal_loopback(0, RX1); -#elif SOC_UART_NUM == 3 +#elif SOC_UART_HP_NUM == 3 selected_serial = &Serial2; #endif @@ -485,7 +485,7 @@ void auto_baudrate_test(void) { selected_serial->begin(0); baudrate = selected_serial->baudRate(); -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 Serial.end(); Serial.begin(115200); #endif @@ -504,7 +504,7 @@ void periman_test(void) { Wire.begin(RX1, TX1); -#if SOC_UART_NUM == 3 +#if SOC_UART_HP_NUM == 3 Wire1.begin(RX2, TX2); #endif @@ -518,11 +518,11 @@ void periman_test(void) { Serial1.setPins(RX1, TX1); -#if SOC_UART_NUM == 3 +#if SOC_UART_HP_NUM == 3 Serial2.setPins(RX2, TX2); uart_internal_loopback(1, RX2); uart_internal_loopback(2, RX1); -#elif SOC_UART_NUM == 2 +#elif SOC_UART_HP_NUM == 2 uart_internal_loopback(1, RX1); #endif @@ -565,19 +565,19 @@ void setup() { while (!Serial) { delay(10); } - log_d("SOC_UART_NUM = %d", SOC_UART_NUM); + log_d("SOC_UART_HP_NUM = %d", SOC_UART_HP_NUM); // Begin needs to be called before setting up the loopback because it creates the serial object start_serial(115200); -#if SOC_UART_NUM == 2 +#if SOC_UART_HP_NUM == 2 log_d("Setup internal loop-back from and back to Serial1 (UART1) TX >> Serial1 (UART1) RX"); Serial1.onReceive([]() { onReceive_cb(Serial1); }); uart_internal_loopback(1, RX1); -#elif SOC_UART_NUM == 3 +#elif SOC_UART_HP_NUM == 3 log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)"); Serial1.onReceive([]() { From f77ce040db4504c91f918874bab5af52dfdb58a6 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 20 Aug 2024 00:51:23 +0300 Subject: [PATCH 002/406] fix(build): Fix many warnings --- cores/esp32/esp32-hal-cpu.c | 8 ++-- cores/esp32/esp32-hal-misc.c | 10 ++--- .../BluetoothSerial/src/BluetoothSerial.cpp | 2 +- libraries/ESP_I2S/src/ESP_I2S.cpp | 2 +- libraries/Ethernet/src/ETH.cpp | 4 +- libraries/SD_MMC/src/SD_MMC.cpp | 3 +- libraries/WiFi/src/WiFiGeneric.cpp | 43 ++++++++++--------- 7 files changed, 37 insertions(+), 35 deletions(-) diff --git a/cores/esp32/esp32-hal-cpu.c b/cores/esp32/esp32-hal-cpu.c index 7027c7cad9d..2420dfbeeb0 100644 --- a/cores/esp32/esp32-hal-cpu.c +++ b/cores/esp32/esp32-hal-cpu.c @@ -21,7 +21,7 @@ #include "soc/rtc.h" #if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) #include "soc/rtc_cntl_reg.h" -#include "soc/apb_ctrl_reg.h" +#include "soc/syscon_reg.h" #endif #include "soc/efuse_reg.h" #include "esp32-hal.h" @@ -30,13 +30,13 @@ #include "esp_system.h" #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 -#include "freertos/xtensa_timer.h" +#include "xtensa_timer.h" #include "esp32/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32S2 -#include "freertos/xtensa_timer.h" +#include "xtensa_timer.h" #include "esp32s2/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32S3 -#include "freertos/xtensa_timer.h" +#include "xtensa_timer.h" #include "esp32s3/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C2 #include "esp32c2/rom/rtc.h" diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index 82363b97bd0..7dfca6134b2 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -31,7 +31,7 @@ #include "soc/rtc.h" #if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) #include "soc/rtc_cntl_reg.h" -#include "soc/apb_ctrl_reg.h" +#include "soc/syscon_reg.h" #endif #include "esp_task_wdt.h" #include "esp32-hal.h" @@ -147,14 +147,14 @@ void feedLoopWDT() { #endif void enableCore0WDT() { - TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCore(0); if (idle_0 == NULL || esp_task_wdt_add(idle_0) != ESP_OK) { log_e("Failed to add Core 0 IDLE task to WDT"); } } void disableCore0WDT() { - TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCore(0); if (idle_0 == NULL || esp_task_wdt_delete(idle_0) != ESP_OK) { log_e("Failed to remove Core 0 IDLE task from WDT"); } @@ -162,14 +162,14 @@ void disableCore0WDT() { #ifndef CONFIG_FREERTOS_UNICORE void enableCore1WDT() { - TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCore(1); if (idle_1 == NULL || esp_task_wdt_add(idle_1) != ESP_OK) { log_e("Failed to add Core 1 IDLE task to WDT"); } } void disableCore1WDT() { - TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCore(1); if (idle_1 == NULL || esp_task_wdt_delete(idle_1) != ESP_OK) { log_e("Failed to remove Core 1 IDLE task from WDT"); } diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/libraries/BluetoothSerial/src/BluetoothSerial.cpp index 12c09d68305..3d00504c1b1 100644 --- a/libraries/BluetoothSerial/src/BluetoothSerial.cpp +++ b/libraries/BluetoothSerial/src/BluetoothSerial.cpp @@ -698,7 +698,7 @@ static bool _init_bt(const char *deviceName, bt_mode mode) { } log_i("device name set"); - esp_bt_dev_set_device_name(deviceName); + esp_bt_gap_set_device_name(deviceName); if (_enableSSP) { log_i("Simple Secure Pairing"); diff --git a/libraries/ESP_I2S/src/ESP_I2S.cpp b/libraries/ESP_I2S/src/ESP_I2S.cpp index 50f76b41a3f..8b136ba5c47 100644 --- a/libraries/ESP_I2S/src/ESP_I2S.cpp +++ b/libraries/ESP_I2S/src/ESP_I2S.cpp @@ -12,7 +12,7 @@ #define I2S_READ_CHUNK_SIZE 1920 #define I2S_DEFAULT_CFG() \ - { .id = I2S_NUM_AUTO, .role = I2S_ROLE_MASTER, .dma_desc_num = 6, .dma_frame_num = 240, .auto_clear = true, } + { .id = I2S_NUM_AUTO, .role = I2S_ROLE_MASTER, .dma_desc_num = 6, .dma_frame_num = 240, .auto_clear = true, .auto_clear_before_cb = false, .intr_priority = 0 } #define I2S_STD_CHAN_CFG(_sample_rate, _data_bit_width, _slot_mode) \ { \ diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index 48e8460fe2d..bc5a94484da 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -181,8 +181,8 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i : (2 == clock_mode) ? EMAC_CLK_OUT_GPIO : (3 == clock_mode) ? EMAC_CLK_OUT_180_GPIO : EMAC_CLK_IN_GPIO; - mac_config.smi_mdc_gpio_num = digitalPinToGPIONumber(mdc); - mac_config.smi_mdio_gpio_num = digitalPinToGPIONumber(mdio); + mac_config.smi_gpio.mdc_num = digitalPinToGPIONumber(mdc); + mac_config.smi_gpio.mdio_num = digitalPinToGPIONumber(mdio); _pin_mcd = digitalPinToGPIONumber(mdc); _pin_mdio = digitalPinToGPIONumber(mdio); diff --git a/libraries/SD_MMC/src/SD_MMC.cpp b/libraries/SD_MMC/src/SD_MMC.cpp index 13e5fcf27fc..024f8b4e3d7 100644 --- a/libraries/SD_MMC/src/SD_MMC.cpp +++ b/libraries/SD_MMC/src/SD_MMC.cpp @@ -175,7 +175,8 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_ _mode1bit = mode1bit; esp_vfs_fat_sdmmc_mount_config_t mount_config = { - .format_if_mount_failed = format_if_mount_failed, .max_files = maxOpenFiles, .allocation_unit_size = 0, .disk_status_check_enable = false + .format_if_mount_failed = format_if_mount_failed, .max_files = maxOpenFiles, .allocation_unit_size = 0, .disk_status_check_enable = false, + .use_one_fat = false }; esp_err_t ret = esp_vfs_fat_sdmmc_mount(mountpoint, &host, &slot_config, &mount_config, &_card); diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index 6ddf384d009..ccc9518132b 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -39,6 +39,7 @@ extern "C" { #include #include #include +#include #include "lwip/ip_addr.h" #include "lwip/opt.h" #include "lwip/err.h" @@ -693,9 +694,9 @@ bool WiFiGenericClass::initiateFTM(uint8_t frm_count, uint16_t burst_period, uin */ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2, wifi_rx_ant_t rx_mode, wifi_tx_ant_t tx_mode) { - wifi_ant_gpio_config_t wifi_ant_io; + esp_phy_ant_gpio_config_t wifi_ant_io; - if (ESP_OK != esp_wifi_get_ant_gpio(&wifi_ant_io)) { + if (ESP_OK != esp_phy_get_ant_gpio(&wifi_ant_io)) { log_e("Failed to get antenna configuration"); return false; } @@ -705,56 +706,56 @@ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2 wifi_ant_io.gpio_cfg[1].gpio_num = gpio_ant2; wifi_ant_io.gpio_cfg[1].gpio_select = 1; - if (ESP_OK != esp_wifi_set_ant_gpio(&wifi_ant_io)) { + if (ESP_OK != esp_phy_set_ant_gpio(&wifi_ant_io)) { log_e("Failed to set antenna GPIO configuration"); return false; } // Set antenna default configuration - wifi_ant_config_t ant_config = { - .rx_ant_mode = WIFI_ANT_MODE_AUTO, - .rx_ant_default = WIFI_ANT_MAX, // Ignored in AUTO mode - .tx_ant_mode = WIFI_ANT_MODE_AUTO, + esp_phy_ant_config_t ant_config = { + .rx_ant_mode = ESP_PHY_ANT_MODE_AUTO, + .rx_ant_default = ESP_PHY_ANT_MAX, // Ignored in AUTO mode + .tx_ant_mode = ESP_PHY_ANT_MODE_AUTO, .enabled_ant0 = 1, .enabled_ant1 = 2, }; switch (rx_mode) { - case WIFI_RX_ANT0: ant_config.rx_ant_mode = WIFI_ANT_MODE_ANT0; break; - case WIFI_RX_ANT1: ant_config.rx_ant_mode = WIFI_ANT_MODE_ANT1; break; + case WIFI_RX_ANT0: ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_ANT0; break; + case WIFI_RX_ANT1: ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_ANT1; break; case WIFI_RX_ANT_AUTO: log_i("TX Antenna will be automatically selected"); - ant_config.rx_ant_default = WIFI_ANT_ANT0; - ant_config.rx_ant_mode = WIFI_ANT_MODE_AUTO; + ant_config.rx_ant_default = ESP_PHY_ANT_ANT0; + ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO; // Force TX for AUTO if RX is AUTO - ant_config.tx_ant_mode = WIFI_ANT_MODE_AUTO; + ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO; goto set_ant; break; default: log_e("Invalid default antenna! Falling back to AUTO"); - ant_config.rx_ant_mode = WIFI_ANT_MODE_AUTO; + ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO; break; } switch (tx_mode) { - case WIFI_TX_ANT0: ant_config.tx_ant_mode = WIFI_ANT_MODE_ANT0; break; - case WIFI_TX_ANT1: ant_config.tx_ant_mode = WIFI_ANT_MODE_ANT1; break; + case WIFI_TX_ANT0: ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_ANT0; break; + case WIFI_TX_ANT1: ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_ANT1; break; case WIFI_TX_ANT_AUTO: log_i("RX Antenna will be automatically selected"); - ant_config.rx_ant_default = WIFI_ANT_ANT0; - ant_config.tx_ant_mode = WIFI_ANT_MODE_AUTO; + ant_config.rx_ant_default = ESP_PHY_ANT_ANT0; + ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO; // Force RX for AUTO if RX is AUTO - ant_config.rx_ant_mode = WIFI_ANT_MODE_AUTO; + ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO; break; default: log_e("Invalid default antenna! Falling back to AUTO"); - ant_config.rx_ant_default = WIFI_ANT_ANT0; - ant_config.tx_ant_mode = WIFI_ANT_MODE_AUTO; + ant_config.rx_ant_default = ESP_PHY_ANT_ANT0; + ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO; break; } set_ant: - if (ESP_OK != esp_wifi_set_ant(&ant_config)) { + if (ESP_OK != esp_phy_set_ant(&ant_config)) { log_e("Failed to set antenna configuration"); return false; } From 54f1c22672950c5b64af475b5ac4bc1ec9b5ad73 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 20 Aug 2024 01:16:59 +0300 Subject: [PATCH 003/406] fix(build): Fix warning in FFat --- libraries/FFat/src/FFat.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/FFat/src/FFat.cpp b/libraries/FFat/src/FFat.cpp index 1227e172602..41d941b4726 100644 --- a/libraries/FFat/src/FFat.cpp +++ b/libraries/FFat/src/FFat.cpp @@ -46,7 +46,8 @@ bool F_Fat::begin(bool formatOnFail, const char *basePath, uint8_t maxOpenFiles, } esp_vfs_fat_mount_config_t conf = { - .format_if_mount_failed = formatOnFail, .max_files = maxOpenFiles, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false + .format_if_mount_failed = formatOnFail, .max_files = maxOpenFiles, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false, + .use_one_fat = false }; esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(basePath, partitionLabel, &conf, &_wl_handle); if (err) { @@ -98,7 +99,8 @@ bool F_Fat::format(bool full_wipe, char *partitionLabel) { } // Now do a mount with format_if_fail (which it will) esp_vfs_fat_mount_config_t conf = { - .format_if_mount_failed = true, .max_files = 1, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false + .format_if_mount_failed = true, .max_files = 1, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false, + .use_one_fat = false }; result = esp_vfs_fat_spiflash_mount_rw_wl("/format_ffat", partitionLabel, &conf, &temp_handle); esp_vfs_fat_spiflash_unmount_rw_wl("/format_ffat", temp_handle); From c7e01e72a197f8a4982fb0a06838a51d6f72acb0 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 20 Aug 2024 13:02:29 +0300 Subject: [PATCH 004/406] add(build): Add initial ESP32-P4 skeleton Required to start compilation. Board is currently hidden and many options are removed --- boards.txt | 84 +++++++++++++++++++++++++++++++++ idf_component.yml | 1 + variants/esp32p4/pins_arduino.h | 30 ++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 variants/esp32p4/pins_arduino.h diff --git a/boards.txt b/boards.txt index 7ea34347dfe..8b3d48df2fb 100644 --- a/boards.txt +++ b/boards.txt @@ -162,6 +162,90 @@ esp32c2.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +esp32p4.name=ESP32P4 Dev Module +esp32p4.hide=true + +esp32p4.bootloader.tool=esptool_py +esp32p4.bootloader.tool.default=esptool_py + +esp32p4.upload.tool=esptool_py +esp32p4.upload.tool.default=esptool_py +esp32p4.upload.tool.network=esp_ota + +esp32p4.upload.maximum_size=1310720 +esp32p4.upload.maximum_data_size=327680 +esp32p4.upload.flags= +esp32p4.upload.extra_flags= +esp32p4.upload.use_1200bps_touch=false +esp32p4.upload.wait_for_upload_port=false + +esp32p4.serial.disableDTR=false +esp32p4.serial.disableRTS=false + +esp32p4.build.tarch=riscv32 +esp32p4.build.target=esp +esp32p4.build.mcu=esp32p4 +esp32p4.build.core=esp32 +esp32p4.build.variant=esp32p4 +esp32p4.build.board=ESP32P4_DEV +esp32p4.build.bootloader_addr=0x0 + +esp32p4.build.cdc_on_boot=0 +esp32p4.build.f_cpu=400000000L +esp32p4.build.flash_size=4MB +esp32p4.build.flash_freq=80m +esp32p4.build.img_freq=80m +esp32p4.build.flash_mode=qio +esp32p4.build.boot=qio +esp32p4.build.partitions=default +esp32p4.build.defines= + +## IDE 2.0 Seems to not update the value +esp32p4.menu.JTAGAdapter.default=Disabled +esp32p4.menu.JTAGAdapter.default.build.copy_jtag_files=0 + +esp32p4.menu.CDCOnBoot.default=Disabled +esp32p4.menu.CDCOnBoot.default.build.cdc_on_boot=0 +esp32p4.menu.CDCOnBoot.cdc=Enabled +esp32p4.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +esp32p4.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +esp32p4.menu.PartitionScheme.default.build.partitions=default +esp32p4.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +esp32p4.menu.PartitionScheme.no_fs.build.partitions=no_fs +esp32p4.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +esp32p4.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +esp32p4.menu.PartitionScheme.huge_app.build.partitions=huge_app +esp32p4.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +esp32p4.menu.PartitionScheme.custom=Custom +esp32p4.menu.PartitionScheme.custom.build.partitions= +esp32p4.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +esp32p4.menu.UploadSpeed.921600=921600 +esp32p4.menu.UploadSpeed.921600.upload.speed=921600 +esp32p4.menu.UploadSpeed.115200=115200 +esp32p4.menu.UploadSpeed.115200.upload.speed=115200 + +esp32p4.menu.DebugLevel.none=None +esp32p4.menu.DebugLevel.none.build.code_debug=0 +esp32p4.menu.DebugLevel.error=Error +esp32p4.menu.DebugLevel.error.build.code_debug=1 +esp32p4.menu.DebugLevel.warn=Warn +esp32p4.menu.DebugLevel.warn.build.code_debug=2 +esp32p4.menu.DebugLevel.info=Info +esp32p4.menu.DebugLevel.info.build.code_debug=3 +esp32p4.menu.DebugLevel.debug=Debug +esp32p4.menu.DebugLevel.debug.build.code_debug=4 +esp32p4.menu.DebugLevel.verbose=Verbose +esp32p4.menu.DebugLevel.verbose.build.code_debug=5 + +esp32p4.menu.EraseFlash.none=Disabled +esp32p4.menu.EraseFlash.none.upload.erase_cmd= +esp32p4.menu.EraseFlash.all=Enabled +esp32p4.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + esp32h2.name=ESP32H2 Dev Module esp32h2.bootloader.tool=esptool_py diff --git a/idf_component.yml b/idf_component.yml index e6831d71b44..55f35376b1b 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -9,6 +9,7 @@ targets: - esp32c3 - esp32c6 - esp32h2 + - esp32p4 tags: - arduino files: diff --git a/variants/esp32p4/pins_arduino.h b/variants/esp32p4/pins_arduino.h new file mode 100644 index 00000000000..87d0548cf3c --- /dev/null +++ b/variants/esp32p4/pins_arduino.h @@ -0,0 +1,30 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +#define PIN_NEOPIXEL 44 +// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino +static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_NEOPIXEL; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN +// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() +#define RGB_BUILTIN LED_BUILTIN +#define RGB_BRIGHTNESS 64 + +// BOOT_MODE 35 +// BOOT_MODE2 36 pullup + +static const uint8_t TX = 37; +static const uint8_t RX = 38; + +static const uint8_t SDA = 7; +static const uint8_t SCL = 8; + +static const uint8_t SS = 10; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 12; +static const uint8_t SCK = 13; + +#endif /* Pins_Arduino_h */ From 4c4906f4703821d100bf353ec425057c7569f78b Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 28 Aug 2024 04:50:49 -0300 Subject: [PATCH 005/406] fix(uart): sleep retention (#10248) * fix(uart): sleep retention sets new flag from IDF 5.3 that causes error with Serial.begin(115200). * fix(typo): typo and commentaries * feat(uart): adds memset to make structure empty * fix(uart): missing parentesis - typo * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- cores/esp32/esp32-hal-uart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index e4432f5110f..c2065e806c4 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -497,6 +497,8 @@ uart_t *uartBegin( log_v("UART%d not installed. Starting installation", uart_nr); } uart_config_t uart_config; + memset(&uart_config, 0, sizeof(uart_config_t)); + uart_config.flags.backup_before_sleep = false; // new flag from IDF v5.3 uart_config.data_bits = (config & 0xc) >> 2; uart_config.parity = (config & 0x3); uart_config.stop_bits = (config & 0x30) >> 4; From 0b842442c96e963c2f35b8b65e8879b7af16d1e3 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 28 Aug 2024 16:11:35 +0300 Subject: [PATCH 006/406] Update core version to 3.1.0 --- cores/esp32/esp_arduino_version.h | 4 ++-- libraries/ArduinoOTA/library.properties | 2 +- libraries/AsyncUDP/library.properties | 2 +- libraries/BLE/library.properties | 2 +- libraries/BluetoothSerial/library.properties | 2 +- libraries/DNSServer/library.properties | 2 +- libraries/EEPROM/library.properties | 2 +- libraries/ESP32/library.properties | 2 +- libraries/ESP_I2S/library.properties | 2 +- libraries/ESP_NOW/library.properties | 2 +- libraries/ESP_SR/library.properties | 2 +- libraries/ESPmDNS/library.properties | 2 +- libraries/Ethernet/library.properties | 2 +- libraries/FFat/library.properties | 2 +- libraries/FS/library.properties | 2 +- libraries/HTTPClient/library.properties | 2 +- libraries/HTTPUpdate/library.properties | 2 +- libraries/HTTPUpdateServer/library.properties | 2 +- libraries/Insights/library.properties | 2 +- libraries/LittleFS/library.properties | 2 +- libraries/NetBIOS/library.properties | 2 +- libraries/Network/library.properties | 2 +- libraries/NetworkClientSecure/library.properties | 2 +- libraries/OpenThread/library.properties | 2 +- libraries/PPP/library.properties | 2 +- libraries/Preferences/library.properties | 2 +- libraries/RainMaker/library.properties | 2 +- libraries/SD/library.properties | 2 +- libraries/SD_MMC/library.properties | 2 +- libraries/SPI/library.properties | 2 +- libraries/SPIFFS/library.properties | 2 +- libraries/SimpleBLE/library.properties | 2 +- libraries/TFLiteMicro/library.properties | 2 +- libraries/Ticker/library.properties | 2 +- libraries/USB/library.properties | 2 +- libraries/Update/library.properties | 2 +- libraries/WebServer/library.properties | 2 +- libraries/WiFi/library.properties | 2 +- libraries/WiFiProv/library.properties | 2 +- libraries/Wire/library.properties | 2 +- package.json | 2 +- platform.txt | 2 +- 42 files changed, 43 insertions(+), 43 deletions(-) diff --git a/cores/esp32/esp_arduino_version.h b/cores/esp32/esp_arduino_version.h index adc8415dbd9..c2921b95fb8 100644 --- a/cores/esp32/esp_arduino_version.h +++ b/cores/esp32/esp_arduino_version.h @@ -21,9 +21,9 @@ extern "C" { /** Major version number (X.x.x) */ #define ESP_ARDUINO_VERSION_MAJOR 3 /** Minor version number (x.X.x) */ -#define ESP_ARDUINO_VERSION_MINOR 0 +#define ESP_ARDUINO_VERSION_MINOR 1 /** Patch version number (x.x.X) */ -#define ESP_ARDUINO_VERSION_PATCH 4 +#define ESP_ARDUINO_VERSION_PATCH 0 /** * Macro to convert ARDUINO version number into an integer diff --git a/libraries/ArduinoOTA/library.properties b/libraries/ArduinoOTA/library.properties index a8336230f79..54ad6eafb21 100644 --- a/libraries/ArduinoOTA/library.properties +++ b/libraries/ArduinoOTA/library.properties @@ -1,5 +1,5 @@ name=ArduinoOTA -version=3.0.4 +version=3.1.0 author=Ivan Grokhotkov and Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download. diff --git a/libraries/AsyncUDP/library.properties b/libraries/AsyncUDP/library.properties index 92332f78599..24457a39b90 100644 --- a/libraries/AsyncUDP/library.properties +++ b/libraries/AsyncUDP/library.properties @@ -1,5 +1,5 @@ name=ESP32 Async UDP -version=3.0.4 +version=3.1.0 author=Me-No-Dev maintainer=Me-No-Dev sentence=Async UDP Library for ESP32 diff --git a/libraries/BLE/library.properties b/libraries/BLE/library.properties index 82395a1f6d5..32ad36b5f44 100644 --- a/libraries/BLE/library.properties +++ b/libraries/BLE/library.properties @@ -1,5 +1,5 @@ name=BLE -version=3.0.4 +version=3.1.0 author=Neil Kolban maintainer=Dariusz Krempa sentence=BLE functions for ESP32 diff --git a/libraries/BluetoothSerial/library.properties b/libraries/BluetoothSerial/library.properties index a91e8455e05..6db3a01bb19 100644 --- a/libraries/BluetoothSerial/library.properties +++ b/libraries/BluetoothSerial/library.properties @@ -1,5 +1,5 @@ name=BluetoothSerial -version=3.0.4 +version=3.1.0 author=Evandro Copercini maintainer=Evandro Copercini sentence=Simple UART to Classical Bluetooth bridge for ESP32 diff --git a/libraries/DNSServer/library.properties b/libraries/DNSServer/library.properties index bb4ed950fad..077d9237f21 100644 --- a/libraries/DNSServer/library.properties +++ b/libraries/DNSServer/library.properties @@ -1,5 +1,5 @@ name=DNSServer -version=3.0.4 +version=3.1.0 author=Kristijan Novoselić maintainer=Kristijan Novoselić, sentence=A simple DNS server for ESP32. diff --git a/libraries/EEPROM/library.properties b/libraries/EEPROM/library.properties index 6297bedcb22..bf75d618898 100644 --- a/libraries/EEPROM/library.properties +++ b/libraries/EEPROM/library.properties @@ -1,5 +1,5 @@ name=EEPROM -version=3.0.4 +version=3.1.0 author=Ivan Grokhotkov maintainer=Paolo Becchi sentence=Enables reading and writing data a sequential, addressable FLASH storage diff --git a/libraries/ESP32/library.properties b/libraries/ESP32/library.properties index c0897f23eee..1bb1ed21750 100644 --- a/libraries/ESP32/library.properties +++ b/libraries/ESP32/library.properties @@ -1,5 +1,5 @@ name=ESP32 -version=3.0.4 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 sketches examples diff --git a/libraries/ESP_I2S/library.properties b/libraries/ESP_I2S/library.properties index ad0e4fbdc59..807f7daeb9d 100644 --- a/libraries/ESP_I2S/library.properties +++ b/libraries/ESP_I2S/library.properties @@ -1,5 +1,5 @@ name=ESP_I2S -version=3.0.4 +version=3.1.0 author=me-no-dev maintainer=me-no-dev sentence=Library for ESP I2S communication diff --git a/libraries/ESP_NOW/library.properties b/libraries/ESP_NOW/library.properties index 1d1dc8926a1..42876f47f95 100644 --- a/libraries/ESP_NOW/library.properties +++ b/libraries/ESP_NOW/library.properties @@ -1,5 +1,5 @@ name=ESP_NOW -version=3.0.4 +version=3.1.0 author=me-no-dev maintainer=P-R-O-C-H-Y sentence=Library for ESP_NOW diff --git a/libraries/ESP_SR/library.properties b/libraries/ESP_SR/library.properties index bf3ab3a14ba..a81cff2fe9d 100644 --- a/libraries/ESP_SR/library.properties +++ b/libraries/ESP_SR/library.properties @@ -1,5 +1,5 @@ name=ESP_SR -version=3.0.4 +version=3.1.0 author=me-no-dev maintainer=me-no-dev sentence=Library for ESP Sound Recognition diff --git a/libraries/ESPmDNS/library.properties b/libraries/ESPmDNS/library.properties index 64ff66c3a1e..4f65114fd0b 100644 --- a/libraries/ESPmDNS/library.properties +++ b/libraries/ESPmDNS/library.properties @@ -1,5 +1,5 @@ name=ESPmDNS -version=3.0.4 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 mDNS Library diff --git a/libraries/Ethernet/library.properties b/libraries/Ethernet/library.properties index 1fc7df2192d..70aa24ec4aa 100644 --- a/libraries/Ethernet/library.properties +++ b/libraries/Ethernet/library.properties @@ -1,5 +1,5 @@ name=Ethernet -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables network connection (local and Internet) using the ESP32 Ethernet. diff --git a/libraries/FFat/library.properties b/libraries/FFat/library.properties index 87dda7b1299..dae11e43aaf 100644 --- a/libraries/FFat/library.properties +++ b/libraries/FFat/library.properties @@ -1,5 +1,5 @@ name=FFat -version=3.0.4 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov, Larry Bernstone maintainer=Hristo Gochkov sentence=ESP32 FAT on Flash File System diff --git a/libraries/FS/library.properties b/libraries/FS/library.properties index 676faf43e99..009383ab0c8 100644 --- a/libraries/FS/library.properties +++ b/libraries/FS/library.properties @@ -1,5 +1,5 @@ name=FS -version=3.0.4 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 File System diff --git a/libraries/HTTPClient/library.properties b/libraries/HTTPClient/library.properties index 40da6a0cde9..203b8929d30 100644 --- a/libraries/HTTPClient/library.properties +++ b/libraries/HTTPClient/library.properties @@ -1,5 +1,5 @@ name=HTTPClient -version=3.0.4 +version=3.1.0 author=Markus Sattler maintainer=Markus Sattler sentence=HTTP Client for ESP32 diff --git a/libraries/HTTPUpdate/library.properties b/libraries/HTTPUpdate/library.properties index ab7e9b6f872..ac903dd71cf 100644 --- a/libraries/HTTPUpdate/library.properties +++ b/libraries/HTTPUpdate/library.properties @@ -1,5 +1,5 @@ name=HTTPUpdate -version=3.0.4 +version=3.1.0 author=Markus Sattler maintainer=Markus Sattler sentence=Http Update for ESP32 diff --git a/libraries/HTTPUpdateServer/library.properties b/libraries/HTTPUpdateServer/library.properties index 249eb5ea173..b26bd2cad7b 100644 --- a/libraries/HTTPUpdateServer/library.properties +++ b/libraries/HTTPUpdateServer/library.properties @@ -1,5 +1,5 @@ name=HTTPUpdateServer -version=3.0.4 +version=3.1.0 author=Hristo Kapanakov maintainer= sentence=Simple HTTP Update server based on the WebServer diff --git a/libraries/Insights/library.properties b/libraries/Insights/library.properties index cabf05f2806..af213a1e70d 100644 --- a/libraries/Insights/library.properties +++ b/libraries/Insights/library.properties @@ -1,5 +1,5 @@ name=ESP Insights -version=3.0.4 +version=3.1.0 author=Sanket Wadekar maintainer=Sanket Wadekar sentence=ESP Insights diff --git a/libraries/LittleFS/library.properties b/libraries/LittleFS/library.properties index f443b70bc2f..86c4c43eeca 100644 --- a/libraries/LittleFS/library.properties +++ b/libraries/LittleFS/library.properties @@ -1,5 +1,5 @@ name=LittleFS -version=3.0.4 +version=3.1.0 author= maintainer= sentence=LittleFS for esp32 diff --git a/libraries/NetBIOS/library.properties b/libraries/NetBIOS/library.properties index fdf9b63a0d2..42555781f75 100644 --- a/libraries/NetBIOS/library.properties +++ b/libraries/NetBIOS/library.properties @@ -1,5 +1,5 @@ name=NetBIOS -version=3.0.4 +version=3.1.0 author=Pablo@xpablo.cz maintainer=Hristo Gochkov sentence=Enables NBNS (NetBIOS) name resolution. diff --git a/libraries/Network/library.properties b/libraries/Network/library.properties index 49aadb7b874..8a1567e68a9 100644 --- a/libraries/Network/library.properties +++ b/libraries/Network/library.properties @@ -1,5 +1,5 @@ name=Networking -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=General network management library. diff --git a/libraries/NetworkClientSecure/library.properties b/libraries/NetworkClientSecure/library.properties index 2a0ca88ffbe..d810e852524 100644 --- a/libraries/NetworkClientSecure/library.properties +++ b/libraries/NetworkClientSecure/library.properties @@ -1,5 +1,5 @@ name=NetworkClientSecure -version=3.0.4 +version=3.1.0 author=Evandro Luis Copercini maintainer=Github Community sentence=Enables secure network connection (local and Internet) using the ESP32 built-in WiFi. diff --git a/libraries/OpenThread/library.properties b/libraries/OpenThread/library.properties index 6a16dabddd0..19d37749a92 100644 --- a/libraries/OpenThread/library.properties +++ b/libraries/OpenThread/library.properties @@ -1,5 +1,5 @@ name=OpenThread -version=3.0.4 +version=3.1.0 author=Rodrigo Garcia | GitHub @SuGlider maintainer=Rodrigo Garcia sentence=Library for OpenThread Network on ESP32. diff --git a/libraries/PPP/library.properties b/libraries/PPP/library.properties index 0403b576df2..e2b290cc893 100644 --- a/libraries/PPP/library.properties +++ b/libraries/PPP/library.properties @@ -1,5 +1,5 @@ name=PPP -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables network connection using GSM Modem. diff --git a/libraries/Preferences/library.properties b/libraries/Preferences/library.properties index 8437425c04d..90cd20d75c3 100644 --- a/libraries/Preferences/library.properties +++ b/libraries/Preferences/library.properties @@ -1,5 +1,5 @@ name=Preferences -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Provides friendly access to ESP32's Non-Volatile Storage diff --git a/libraries/RainMaker/library.properties b/libraries/RainMaker/library.properties index e6bdd2f4579..0c3e6e26697 100644 --- a/libraries/RainMaker/library.properties +++ b/libraries/RainMaker/library.properties @@ -1,5 +1,5 @@ name=ESP RainMaker -version=3.0.4 +version=3.1.0 author=Sweety Mhaiske maintainer=Hristo Gochkov sentence=ESP RainMaker Support diff --git a/libraries/SD/library.properties b/libraries/SD/library.properties index 98d93943a7f..3fd1a3f8a3e 100644 --- a/libraries/SD/library.properties +++ b/libraries/SD/library.properties @@ -1,5 +1,5 @@ name=SD -version=3.0.4 +version=3.1.0 author=Arduino, SparkFun maintainer=Arduino sentence=Enables reading and writing on SD cards. For all Arduino boards. diff --git a/libraries/SD_MMC/library.properties b/libraries/SD_MMC/library.properties index 242fc62ecac..94586e8e1ec 100644 --- a/libraries/SD_MMC/library.properties +++ b/libraries/SD_MMC/library.properties @@ -1,5 +1,5 @@ name=SD_MMC -version=3.0.4 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 SDMMC File System diff --git a/libraries/SPI/library.properties b/libraries/SPI/library.properties index 804f86e93c2..a7a7204db62 100644 --- a/libraries/SPI/library.properties +++ b/libraries/SPI/library.properties @@ -1,5 +1,5 @@ name=SPI -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE. diff --git a/libraries/SPIFFS/library.properties b/libraries/SPIFFS/library.properties index 9aaf1d9c575..132ff5fb7f1 100644 --- a/libraries/SPIFFS/library.properties +++ b/libraries/SPIFFS/library.properties @@ -1,5 +1,5 @@ name=SPIFFS -version=3.0.4 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 SPIFFS File System diff --git a/libraries/SimpleBLE/library.properties b/libraries/SimpleBLE/library.properties index c49cd51b389..ae28a21c0df 100644 --- a/libraries/SimpleBLE/library.properties +++ b/libraries/SimpleBLE/library.properties @@ -1,5 +1,5 @@ name=SimpleBLE -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Provides really simple BLE advertizer with just on and off diff --git a/libraries/TFLiteMicro/library.properties b/libraries/TFLiteMicro/library.properties index 1a966476619..cde7d21bec1 100644 --- a/libraries/TFLiteMicro/library.properties +++ b/libraries/TFLiteMicro/library.properties @@ -1,5 +1,5 @@ name=TFLite Micro -version=3.0.4 +version=3.1.0 author=Sanket Wadekar maintainer=Sanket Wadekar sentence=TensorFlow Lite for Microcontrollers diff --git a/libraries/Ticker/library.properties b/libraries/Ticker/library.properties index 297e3221b1d..d6e9829c6ef 100644 --- a/libraries/Ticker/library.properties +++ b/libraries/Ticker/library.properties @@ -1,5 +1,5 @@ name=Ticker -version=3.0.4 +version=3.1.0 author=Bert Melis maintainer=Hristo Gochkov sentence=Allows to call functions with a given interval. diff --git a/libraries/USB/library.properties b/libraries/USB/library.properties index 209fca7ebc3..752acf3a803 100644 --- a/libraries/USB/library.properties +++ b/libraries/USB/library.properties @@ -1,5 +1,5 @@ name=USB -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=ESP32S2 USB Library diff --git a/libraries/Update/library.properties b/libraries/Update/library.properties index b70add08cad..9d480986b1e 100644 --- a/libraries/Update/library.properties +++ b/libraries/Update/library.properties @@ -1,5 +1,5 @@ name=Update -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=ESP32 Sketch Update Library diff --git a/libraries/WebServer/library.properties b/libraries/WebServer/library.properties index 10dc2ff1a4f..89e35e4713d 100644 --- a/libraries/WebServer/library.properties +++ b/libraries/WebServer/library.properties @@ -1,5 +1,5 @@ name=WebServer -version=3.0.4 +version=3.1.0 author=Ivan Grokhotkov maintainer=Ivan Grokhtkov sentence=Simple web server library diff --git a/libraries/WiFi/library.properties b/libraries/WiFi/library.properties index 5acbee86744..925616ea561 100644 --- a/libraries/WiFi/library.properties +++ b/libraries/WiFi/library.properties @@ -1,5 +1,5 @@ name=WiFi -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables network connection (local and Internet) using the ESP32 built-in WiFi. diff --git a/libraries/WiFiProv/library.properties b/libraries/WiFiProv/library.properties index 886697c9af9..20e27fc5097 100644 --- a/libraries/WiFiProv/library.properties +++ b/libraries/WiFiProv/library.properties @@ -1,5 +1,5 @@ name=WiFiProv -version=3.0.4 +version=3.1.0 author=Switi Mhaiske maintainer=Hristo Gochkov sentence=Enables provisioning. diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties index 0c7fa749a7b..a2d79eee81b 100644 --- a/libraries/Wire/library.properties +++ b/libraries/Wire/library.properties @@ -1,5 +1,5 @@ name=Wire -version=3.0.4 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For esp8266 boards. diff --git a/package.json b/package.json index 487bcc77a2c..2e53f41d4c8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "framework-arduinoespressif32", - "version": "3.0.4", + "version": "3.1.0", "description": "Arduino Wiring-based Framework for the Espressif ESP32, ESP32-S and ESP32-C series of SoCs", "keywords": [ "framework", diff --git a/platform.txt b/platform.txt index e7b8391b9dc..ebc8d23a5c7 100644 --- a/platform.txt +++ b/platform.txt @@ -1,5 +1,5 @@ name=ESP32 Arduino -version=3.0.4 +version=3.1.0 tools.esp32-arduino-libs.path={runtime.platform.path}/tools/esp32-arduino-libs tools.esp32-arduino-libs.path.windows={runtime.platform.path}\tools\esp32-arduino-libs From 57518b821c338382945bc014c8ddfcb93741acf2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:11:51 +0000 Subject: [PATCH 007/406] ci(pre-commit): Apply automatic fixes --- libraries/ESP_I2S/src/ESP_I2S.cpp | 7 +++++-- libraries/FFat/src/FFat.cpp | 8 +++++--- libraries/SD_MMC/src/SD_MMC.cpp | 5 ++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/libraries/ESP_I2S/src/ESP_I2S.cpp b/libraries/ESP_I2S/src/ESP_I2S.cpp index 8b136ba5c47..395c7b587ed 100644 --- a/libraries/ESP_I2S/src/ESP_I2S.cpp +++ b/libraries/ESP_I2S/src/ESP_I2S.cpp @@ -11,8 +11,11 @@ #define I2S_READ_CHUNK_SIZE 1920 -#define I2S_DEFAULT_CFG() \ - { .id = I2S_NUM_AUTO, .role = I2S_ROLE_MASTER, .dma_desc_num = 6, .dma_frame_num = 240, .auto_clear = true, .auto_clear_before_cb = false, .intr_priority = 0 } +#define I2S_DEFAULT_CFG() \ + { \ + .id = I2S_NUM_AUTO, .role = I2S_ROLE_MASTER, .dma_desc_num = 6, .dma_frame_num = 240, .auto_clear = true, .auto_clear_before_cb = false, \ + .intr_priority = 0 \ + } #define I2S_STD_CHAN_CFG(_sample_rate, _data_bit_width, _slot_mode) \ { \ diff --git a/libraries/FFat/src/FFat.cpp b/libraries/FFat/src/FFat.cpp index 41d941b4726..003339152fe 100644 --- a/libraries/FFat/src/FFat.cpp +++ b/libraries/FFat/src/FFat.cpp @@ -46,7 +46,10 @@ bool F_Fat::begin(bool formatOnFail, const char *basePath, uint8_t maxOpenFiles, } esp_vfs_fat_mount_config_t conf = { - .format_if_mount_failed = formatOnFail, .max_files = maxOpenFiles, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false, + .format_if_mount_failed = formatOnFail, + .max_files = maxOpenFiles, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, + .disk_status_check_enable = false, .use_one_fat = false }; esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(basePath, partitionLabel, &conf, &_wl_handle); @@ -99,8 +102,7 @@ bool F_Fat::format(bool full_wipe, char *partitionLabel) { } // Now do a mount with format_if_fail (which it will) esp_vfs_fat_mount_config_t conf = { - .format_if_mount_failed = true, .max_files = 1, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false, - .use_one_fat = false + .format_if_mount_failed = true, .max_files = 1, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false, .use_one_fat = false }; result = esp_vfs_fat_spiflash_mount_rw_wl("/format_ffat", partitionLabel, &conf, &temp_handle); esp_vfs_fat_spiflash_unmount_rw_wl("/format_ffat", temp_handle); diff --git a/libraries/SD_MMC/src/SD_MMC.cpp b/libraries/SD_MMC/src/SD_MMC.cpp index 024f8b4e3d7..6bbcf44d010 100644 --- a/libraries/SD_MMC/src/SD_MMC.cpp +++ b/libraries/SD_MMC/src/SD_MMC.cpp @@ -175,7 +175,10 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_ _mode1bit = mode1bit; esp_vfs_fat_sdmmc_mount_config_t mount_config = { - .format_if_mount_failed = format_if_mount_failed, .max_files = maxOpenFiles, .allocation_unit_size = 0, .disk_status_check_enable = false, + .format_if_mount_failed = format_if_mount_failed, + .max_files = maxOpenFiles, + .allocation_unit_size = 0, + .disk_status_check_enable = false, .use_one_fat = false }; From 564612dacc7310a10b9778c5389c15b0db4192eb Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 28 Aug 2024 22:45:33 +0300 Subject: [PATCH 008/406] IDF release/v5.3 0bbd7281 (#10258) --- package/package_esp32_index.template.json | 68 +++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 8c585fa86ed..d14b71a7491 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -42,7 +42,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-466a392a" + "version": "idf-release_v5.3-0bbd7281" }, { "packager": "esp32", @@ -95,63 +95,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-466a392a", + "version": "idf-release_v5.3-0bbd7281", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", - "size": "318864212" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", + "size": "319140606" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", - "size": "318864212" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", + "size": "319140606" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", - "size": "318864212" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", + "size": "319140606" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", - "size": "318864212" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", + "size": "319140606" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", - "size": "318864212" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", + "size": "319140606" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", - "size": "318864212" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", + "size": "319140606" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", - "size": "318864212" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", + "size": "319140606" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-466a392a.zip", - "checksum": "SHA-256:8c2d36bd4be5b6a9446efd3c2b2f93f544f4b2a22dab23c4991aec5711c72884", - "size": "318864212" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", + "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", + "size": "319140606" } ] }, From 67682088cabc60f2b4f6d459d5635245c9ff9ca6 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 18 Sep 2024 15:56:37 +0300 Subject: [PATCH 009/406] IDF release/v5.3 (#10272) * IDF release/v5.3 2c46030b * IDF release/v5.3 cc3203dc * IDF release/v5.3 4d0db704 --- package/package_esp32_index.template.json | 128 +++++++++++----------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index d14b71a7491..701e77b3b21 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -42,7 +42,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-0bbd7281" + "version": "idf-release_v5.3-4d0db704" }, { "packager": "esp32", @@ -67,7 +67,7 @@ { "packager": "esp32", "name": "openocd-esp32", - "version": "v0.12.0-esp32-20240318" + "version": "v0.12.0-esp32-20240821" }, { "packager": "esp32", @@ -95,63 +95,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-0bbd7281", + "version": "idf-release_v5.3-4d0db704", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", - "size": "319140606" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", + "size": "320072134" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", - "size": "319140606" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", + "size": "320072134" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", - "size": "319140606" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", + "size": "320072134" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", - "size": "319140606" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", + "size": "320072134" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", - "size": "319140606" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", + "size": "320072134" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", - "size": "319140606" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", + "size": "320072134" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", - "size": "319140606" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", + "size": "320072134" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-0bbd7281.zip", - "checksum": "SHA-256:e436e8ba703cf78ec81d80e956d2ae4a5e754f280950520ad7c425bb56738a80", - "size": "319140606" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", + "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", + "size": "320072134" } ] }, @@ -405,56 +405,56 @@ }, { "name": "openocd-esp32", - "version": "v0.12.0-esp32-20240318", + "version": "v0.12.0-esp32-20240821", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-linux-amd64-0.12.0-esp32-20240318.tar.gz", - "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20240318.tar.gz", - "checksum": "SHA-256:cf26c5cef4f6b04aa23cd2778675604e5a74a4ce4d8d17b854d05fbcb782d52c", - "size": "2252682" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-amd64-0.12.0-esp32-20240821.tar.gz", + "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20240821.tar.gz", + "checksum": "SHA-256:f8c68541fa38307bc0c0763b7e1e3fe4e943d5d45da07d817a73b492e103b652", + "size": "2373094" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-linux-arm64-0.12.0-esp32-20240318.tar.gz", - "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20240318.tar.gz", - "checksum": "SHA-256:9b97a37aa2cab94424a778c25c0b4aa0f90d6ef9cda764a1d9289d061305f4b7", - "size": "2132904" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-arm64-0.12.0-esp32-20240821.tar.gz", + "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20240821.tar.gz", + "checksum": "SHA-256:4d6e263d84e447354dc685848557d6c284dda7fe007ee451f729a7edfa7baad7", + "size": "2251272" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-linux-armel-0.12.0-esp32-20240318.tar.gz", - "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20240318.tar.gz", - "checksum": "SHA-256:b7e82776ec374983807d3389df09c632ad9bc8341f2075690b6b500319dfeaf4", - "size": "2271761" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-armel-0.12.0-esp32-20240821.tar.gz", + "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20240821.tar.gz", + "checksum": "SHA-256:9d45679f2c4cf450d5e2350047cf57bb76dde2487d30cebce0a72c9173b5c45b", + "size": "2390074" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-macos-0.12.0-esp32-20240318.tar.gz", - "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20240318.tar.gz", - "checksum": "SHA-256:b16c3082c94df1079367c44d99f7a8605534cd48aabc18898e46e94a2c8c57e7", - "size": "2365588" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-macos-0.12.0-esp32-20240821.tar.gz", + "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20240821.tar.gz", + "checksum": "SHA-256:565c8fabc5f19a6e7a0864a294d74b307eec30b9291d16d3fc90e273f0330cb4", + "size": "2485320" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-macos-arm64-0.12.0-esp32-20240318.tar.gz", - "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20240318.tar.gz", - "checksum": "SHA-256:534ec925ae6e35e869e4e4e6e4d2c4a1eb081f97ebcc2dd5efdc52d12f4c2f86", - "size": "2406377" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-macos-arm64-0.12.0-esp32-20240821.tar.gz", + "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20240821.tar.gz", + "checksum": "SHA-256:68c5c7cf3d15b9810939a5edabc6ff2c9f4fc32262de91fc292a180bc5cc0637", + "size": "2530336" }, { "host": "i686-mingw32", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-win32-0.12.0-esp32-20240318.zip", - "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20240318.zip", - "checksum": "SHA-256:d379329eba052435173ab0d69c9b15bc164a6ce489e2a67cd11169d2dabff633", - "size": "2783915" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-win32-0.12.0-esp32-20240821.zip", + "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20240821.zip", + "checksum": "SHA-256:463fc2903ddaf03f86ff50836c5c63cc696550b0446140159eddfd2e85570c5d", + "size": "2916409" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240318/openocd-esp32-win32-0.12.0-esp32-20240318.zip", - "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20240318.zip", - "checksum": "SHA-256:d379329eba052435173ab0d69c9b15bc164a6ce489e2a67cd11169d2dabff633", - "size": "2783915" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-win64-0.12.0-esp32-20240821.zip", + "archiveFileName": "openocd-esp32-win64-0.12.0-esp32-20240821.zip", + "checksum": "SHA-256:550f57369f1f1f6cc600b5dffa3378fd6164d8ea8db7c567cf41091771f090cb", + "size": "2916408" } ] }, From ae052f414ae6eb0f927b1acfb25fa23fa4f91524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Tue, 24 Sep 2024 17:26:34 +0200 Subject: [PATCH 010/406] Update Matter Light README.md (#10357) * Update Matter Light README.md Update Matter Light README.md * fix(matter): information in the commentaries from SuGlider * feat(matter): extended formating used the same formatting for the whole document and changed a few expresssions. * fix(matter): missing option idf.py --------- Co-authored-by: Rodrigo Garcia --- .../esp_matter_light/README.md | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/idf_component_examples/esp_matter_light/README.md b/idf_component_examples/esp_matter_light/README.md index 13a55f8ef64..06a22cdceac 100644 --- a/idf_component_examples/esp_matter_light/README.md +++ b/idf_component_examples/esp_matter_light/README.md @@ -4,11 +4,11 @@ # Managed Component Light -This example is configured by default to work with the ESP32-S3, which has the RGB LED GPIO set as pin 48 and the BOOT button on GPIO 0. +This example sets automatically the RGB LED GPIO and BOOT Button GPIO based on the default pin used by the selected Devkit Board. This example creates a Color Temperature Light device using the esp_matter component downloaded from the [Espressif Component Registry](https://components.espressif.com/) instead of an extra component locally, so the example can work without setting up the esp-matter environment. -See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about building and flashing the firmware. +Read the [documentation](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about building and flashing the firmware. The code is based on the Arduino API and uses Arduino as an IDF Component. @@ -23,12 +23,13 @@ Possible Matter Environments are: (*) Google Home Assistant requires the user to set up a Matter Light using the [Google Home Developer Console](https://developers.home.google.com/codelabs/matter-device#2). It is necessary to create a Matter Light device with VID = 0xFFF1 and PID = 0x8000. Otherwise, the Light won't show up in the GHA APP. This action is necessary because the Firmware uses Testing credentials and Google requires the user to create the testing device before using it. -There is no QR Code to be used when the Smartphone APP wants to add the Matter Device. +**There is no QR Code** to be used when the Smartphone APP wants to add the Matter Device. Please enter the code manually: `34970112332` -The devboard has a built-in LED that will be used as the Matter Light. -The default setting of the code uses pin 48 for the ESP32-S3. -Please change it in `main/matter_accessory_driver.h` or in the `sdkconfig.defaults.` file. +Each Devkit Board has a built-in LED that will be used as the Matter Light. +The default setting for ESP32-S3 is pin 48, for ESP32-C3 and ESP32-C6, it is pin 8. +The BOOT Button pin of ESP32-S3 is GPIO 0, by toher hand, the ESP32-C3 and ESP32-C6 use GPIO 9. +Please change it in using the MenuConfig executing `idf.py menuconfig` and selecting `Menu->Light Matter Accessory` options. ## LED Status and Factory Mode @@ -49,7 +50,8 @@ The built-in BOOT button will toggle On/Off and replicate the new state to the M ## Returning to the Factory State -Holding the BOOT button pressed for more than 10 seconds and then releasing it will erase all Matter and Wi-Fi configuration, forcing it to reset to factory state. After that, the device needs to be commissioned again. Previous setups done in the Smartphone APP won't work again; therefore, the virtual device shall be removed from the APP. +Holding the BOOT button pressed for more than 10 seconds and then releasing it will erase all Matter and Wi-Fi configuration, forcing it to reset to factory state. After that, the device needs to be commissioned again. +Previous setups done in the Smartphone APP won't work again; therefore, the virtual device shall be removed from the APP. ## Building the Application using Wi-Fi and Matter @@ -57,16 +59,26 @@ Use ESP-IDF 5.1.4 from https://github.com/espressif/esp-idf/tree/release/v5.1 This example has been tested with Arduino Core 3.0.4 The project will download all necessary components, including the Arduino Core. -Run `idf.py SDKCONFIG_DEFAULTS="sdkconfig.defaults..idf" -p flash monitor` +Run `idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults..idf" -p flash monitor` Example for ESP32-S3/Linux | macOS: -`idf.py SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32s3" -p /dev/ttyACM0 flash monitor` +``` +idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32s3" -p /dev/ttyACM0 flash monitor +``` Example for ESP32-C3/Windows: -`idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32c3" -p com3 flash monitor` +``` +idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32c3" -p com3 flash monitor +``` It may be necessary to delete some folders and files before running `idf.py` -Linux/macOS: `rm -rf build managed_components sdkconfig dependencies.lock` -Windows: `rmdir /s/q build managed_components` and `del sdkconfig dependencies.lock` +- Linux/macOS: + ``` + rm -rf build managed_components sdkconfig dependencies.lock + ``` +- Windows: + ``` + rmdir /s/q build managed_components && del sdkconfig dependencies.lock + ``` There is a configuration file for these SoC: esp32s3, esp32c3, esp32c6. Those are the tested devices that have a WS2812 RGB LED and can run BLE, Wi-Fi and Matter. @@ -74,17 +86,28 @@ Those are the tested devices that have a WS2812 RGB LED and can run BLE, Wi-Fi a In case it is necessary to change the Button Pin or the REG LED Pin, please use the `menuconfig` `idf.py menuconfig` and change the Menu Option `Light Matter Accessory` -## Using OpenThread with Matter +## Building the Application using OpenThread and Matter -This is possible with the ESP32-C6. -It is neessasy to have a Thread Border Routed in the Matter Environment. Check you matter hardware provider. +This is possible with the ESP32-C6. +It is necessary to have a Thread Border Router in the Matter Environment. +Check your Matter hardware provider. In order to build the application that will use Thread Networking instead of Wi-Fi, please execute: -Example for ESP32-S3/Linux | macOS: -`idf.py SDKCONFIG_DEFAULTS="sdkconfig.defaults.c6_thread" -p /dev/ttyACM0 flash monitor` -Example for ESP32-C3/Windows: -`idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.c6_thread" -p com3 flash monitor` +Example for ESP32-C6/Linux | macOS: +``` +idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.c6_thread" -p /dev/ttyACM0 flash monitor +``` +Example for ESP32-C6/Windows: +``` +idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.c6_thread" -p com3 flash monitor +``` It may be necessary to delete some folders and files before running `idf.py` -Linux/macOS: `rm -rf build managed_components sdkconfig dependencies.lock` -Windows: `rmdir /s/q build managed_components` and `del sdkconfig dependencies.lock` +- Linux/macOS + ``` + rm -rf build managed_components sdkconfig dependencies.lock + ``` +- Windows + ``` + rmdir /s/q build managed_components && del sdkconfig dependencies.lock + ``` From a4c33e3897facd6e6f85547c746d33e9019bb0b2 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:18:28 -0300 Subject: [PATCH 011/406] feat(esp32p4): Add initial ESP32-P4 support (#10358) * feat(esp32p4): Initial changes required for ESP32-P4 * esp32-p4: Initial changes to build with Arduino Signed-off-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * fix(esp32p4): Fix lib builder errors * change(esp32p4): Unhide board * ci(esp32p4): Add ESP32-P4 to workflow * change(esptool): Update esptool to 4.8.0 * fix(build): Fix redefinition errors * fix(build): Remove old commands * change(esptool): Remove unsupported 32-bit tools * fix(get.py): Force exe generation * Revert "fix(get.py): Force exe generation" This reverts commit 979b16b3b19d02917ddccf0139c6913cca618714. * fix(get.py): Fix system check * change(tools): Push generated binaries to PR * ci(esp32p4): Add missing ESP32-P4 entries * fix(esp32p4): Add chip info * fix(esp32p4): Fix build commands * docs(esp32p4): Add missing references to P4 * fix(esp32p4): Fix clock sources definitions * fix(esp32p4): Set CPU frequency to 360 MHz so it is stable in all chips * refactor(esp32p4): Change preprocessor conditionals for maintainability Co-authored-by: me-no-dev * fix(esp32p4): Add missing menu options * fix(esp32p4): Mark as not in development json in readme * fix(esp32p4): Add P4 to ci.json files * ci(pre-commit): Apply automatic fixes * fix(get.py): Remove unused include * ci(pre-commit): Apply automatic fixes * change(tools): Push generated binaries to PR * ci(pre-commit): Apply automatic fixes * fix(ci.json): Fix formatting --------- Signed-off-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Co-authored-by: Jason2866 <24528715+Jason2866@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: me-no-dev Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- .github/scripts/on-push.sh | 1 + .github/scripts/sketch_utils.sh | 4 + .github/workflows/lib.yml | 3 + .github/workflows/push.yml | 2 +- .github/workflows/tests.yml | 4 +- .github/workflows/tests_wokwi.yml | 2 +- README.md | 1 + boards.txt | 91 +- cores/esp32/Esp.cpp | 6 + cores/esp32/HardwareSerial.h | 12 + cores/esp32/chip-debug-report.cpp | 6 + cores/esp32/esp32-hal-adc.c | 10 +- cores/esp32/esp32-hal-cpu.c | 33 +- cores/esp32/esp32-hal-i2c-slave.c | 802 +++++++++--------- cores/esp32/esp32-hal-i2c.c | 17 +- cores/esp32/esp32-hal-ledc.c | 5 + cores/esp32/esp32-hal-matrix.c | 2 + cores/esp32/esp32-hal-misc.c | 4 +- cores/esp32/esp32-hal-psram.c | 2 + cores/esp32/esp32-hal-spi.c | 252 +++--- cores/esp32/esp32-hal-spi.h | 8 +- cores/esp32/esp32-hal-touch.c | 21 +- cores/esp32/esp32-hal-touch.h | 2 + cores/esp32/esp32-hal-uart.c | 20 +- docs/en/lib_builder.rst | 1 + idf_component.yml | 1 + .../ArduinoOTA/examples/BasicOTA/ci.json | 3 +- .../AsyncUDP/examples/AsyncUDPClient/ci.json | 3 +- .../examples/AsyncUDPMulticastServer/ci.json | 3 +- .../AsyncUDP/examples/AsyncUDPServer/ci.json | 3 +- .../BLE/examples/BLE5_extended_scan/ci.json | 1 + .../examples/BLE5_multi_advertising/ci.json | 2 +- .../BLE5_periodic_advertising/ci.json | 6 +- .../BLE/examples/BLE5_periodic_sync/ci.json | 4 + libraries/BLE/examples/Beacon_Scanner/ci.json | 4 + libraries/BLE/examples/Client/ci.json | 2 + .../BLE/examples/EddystoneTLM_Beacon/ci.json | 1 + .../BLE/examples/EddystoneURL_Beacon/ci.json | 1 + libraries/BLE/examples/Notify/ci.json | 2 + libraries/BLE/examples/Scan/ci.json | 1 + libraries/BLE/examples/Server/ci.json | 7 +- .../BLE/examples/Server_multiconnect/ci.json | 5 + libraries/BLE/examples/UART/ci.json | 4 + libraries/BLE/examples/Write/ci.json | 2 + libraries/BLE/examples/iBeacon/ci.json | 2 + .../examples/DiscoverConnect/ci.json | 1 + .../examples/GetLocalMAC/ci.json | 1 + .../examples/SerialToSerialBT/ci.json | 1 + .../examples/SerialToSerialBTM/ci.json | 1 + .../examples/SerialToSerialBT_Legacy/ci.json | 1 + .../examples/SerialToSerialBT_SSP/ci.json | 1 + .../bt_classic_device_discovery/ci.json | 1 + .../examples/bt_remove_paired_devices/ci.json | 1 + .../DNSServer/examples/CaptivePortal/ci.json | 3 +- .../examples/Camera/CameraWebServer/ci.json | 3 +- .../examples/DeepSleep/ExternalWakeUp/ci.json | 3 +- .../DeepSleep/SmoothBlink_ULP_Code/ci.json | 1 + .../examples/RMT/RMTLoopback/RMTLoopback.ino | 2 +- .../ResetReason/ResetReason/ResetReason.ino | 2 + .../ESP32/examples/Time/SimpleTime/ci.json | 3 +- .../examples/Zigbee/Zigbee_Light_Bulb/ci.json | 1 + .../Zigbee/Zigbee_Light_Switch/ci.json | 1 + .../Zigbee/Zigbee_Temperature_Sensor/ci.json | 1 + .../examples/Zigbee/Zigbee_Thermostat/ci.json | 1 + .../examples/ESP_NOW_Broadcast_Master/ci.json | 3 +- .../examples/ESP_NOW_Broadcast_Slave/ci.json | 3 +- .../ESP_NOW/examples/ESP_NOW_Network/ci.json | 3 +- .../ESP_NOW/examples/ESP_NOW_Serial/ci.json | 3 +- libraries/ESP_SR/examples/Basic/ci.json | 1 + .../ESPmDNS/examples/mDNS-SD_Extended/ci.json | 3 +- .../ESPmDNS/examples/mDNS_Web_Server/ci.json | 3 +- .../Ethernet/examples/ETH_WIFI_BRIDGE/ci.json | 3 +- libraries/Ethernet/src/ETH.cpp | 6 +- libraries/FFat/examples/FFat_time/ci.json | 3 +- .../HTTPClient/examples/Authorization/ci.json | 3 +- .../examples/BasicHttpClient/ci.json | 3 +- .../examples/BasicHttpsClient/ci.json | 3 +- .../examples/HTTPClientEnterprise/ci.json | 3 +- .../examples/ReuseConnection/ci.json | 3 +- .../examples/StreamHttpClient/ci.json | 3 +- .../HTTPUpdate/examples/httpUpdate/ci.json | 3 +- .../examples/httpUpdateSPIFFS/ci.json | 3 +- .../examples/httpUpdateSecure/ci.json | 3 +- .../examples/WebUpdater/ci.json | 3 +- .../examples/DiagnosticsSmokeTest/ci.json | 3 +- .../examples/MinimalDiagnostics/ci.json | 3 +- .../LittleFS/examples/LITTLEFS_time/ci.json | 3 +- libraries/NetBIOS/examples/ESP_NBNST/ci.json | 3 +- .../examples/WiFiClientInsecure/ci.json | 3 +- .../examples/WiFiClientPSK/ci.json | 3 +- .../examples/WiFiClientSecure/ci.json | 3 +- .../WiFiClientSecureEnterprise/ci.json | 3 +- .../WiFiClientSecureProtocolUpgrade/ci.json | 3 +- .../WiFiClientShowPeerCredentials/ci.json | 3 +- .../WiFiClientTrustOnFirstUse/ci.json | 3 +- .../examples/COAP/coap_lamp/ci.json | 1 + .../examples/COAP/coap_switch/ci.json | 7 +- .../OpenThread/examples/SimpleCLI/ci.json | 8 +- .../OpenThread/examples/SimpleNode/ci.json | 6 +- .../ExtendedRouterNode/ci.json | 8 +- .../SimpleThreadNetwork/LeaderNode/ci.json | 1 + .../SimpleThreadNetwork/RouterNode/ci.json | 1 + .../OpenThread/examples/ThreadScan/ci.json | 1 + .../OpenThread/examples/onReceive/ci.json | 1 + .../PPP/examples/PPP_WIFI_BRIDGE/ci.json | 3 +- libraries/PPP/src/PPP.cpp | 6 +- .../RainMaker/examples/RMakerCustom/ci.json | 3 +- .../examples/RMakerCustomAirCooler/ci.json | 3 +- .../examples/RMakerSonoffDualR3/ci.json | 3 +- .../RainMaker/examples/RMakerSwitch/ci.json | 3 +- libraries/SD/examples/SD_time/ci.json | 3 +- libraries/SD_MMC/examples/SD2USBMSC/ci.json | 1 + libraries/SD_MMC/examples/SDMMC_Test/ci.json | 1 + libraries/SD_MMC/examples/SDMMC_time/ci.json | 1 + libraries/SD_MMC/src/SD_MMC.cpp | 14 +- libraries/SPI/src/SPI.cpp | 2 +- libraries/SPIFFS/examples/SPIFFS_time/ci.json | 3 +- .../examples/SimpleBleDevice/ci.json | 1 + .../Update/examples/AWS_S3_OTA_Update/ci.json | 3 +- .../Update/examples/HTTPS_OTA_Update/ci.json | 3 +- .../HTTP_Client_AES_OTA_Update/ci.json | 3 +- .../HTTP_Server_AES_OTA_Update/ci.json | 3 +- .../Update/examples/OTAWebUpdater/ci.json | 3 +- .../examples/AdvancedWebServer/ci.json | 3 +- .../WebServer/examples/FSBrowser/ci.json | 3 +- libraries/WebServer/examples/Filters/ci.json | 3 +- .../WebServer/examples/HelloServer/ci.json | 3 +- .../examples/HttpAdvancedAuth/ci.json | 3 +- .../examples/HttpAuthCallback/ci.json | 3 +- .../examples/HttpAuthCallbackInline/ci.json | 3 +- .../WebServer/examples/HttpBasicAuth/ci.json | 3 +- .../examples/HttpBasicAuthSHA1/ci.json | 3 +- .../HttpBasicAuthSHA1orBearerToken/ci.json | 3 +- .../examples/MultiHomedServers/ci.json | 3 +- .../WebServer/examples/PathArgServer/ci.json | 3 +- .../WebServer/examples/SDWebServer/ci.json | 3 +- .../examples/SimpleAuthentification/ci.json | 3 +- .../WebServer/examples/UploadHugeFile/ci.json | 3 +- .../WebServer/examples/WebServer/ci.json | 3 +- .../WebServer/examples/WebUpdate/ci.json | 3 +- .../WiFi/examples/FTM/FTM_Initiator/ci.json | 3 +- .../WiFi/examples/FTM/FTM_Responder/ci.json | 3 +- .../WiFi/examples/SimpleWiFiServer/ci.json | 3 +- libraries/WiFi/examples/WPS/ci.json | 3 +- .../WiFi/examples/WiFiAccessPoint/ci.json | 3 +- .../WiFi/examples/WiFiBlueToothSwitch/ci.json | 1 + libraries/WiFi/examples/WiFiClient/ci.json | 3 +- .../WiFi/examples/WiFiClientBasic/ci.json | 3 +- .../WiFi/examples/WiFiClientConnect/ci.json | 3 +- .../examples/WiFiClientEnterprise/ci.json | 3 +- .../WiFi/examples/WiFiClientEvents/ci.json | 3 +- .../WiFi/examples/WiFiClientStaticIP/ci.json | 3 +- libraries/WiFi/examples/WiFiExtender/ci.json | 3 +- libraries/WiFi/examples/WiFiIPv6/ci.json | 3 +- libraries/WiFi/examples/WiFiMulti/ci.json | 3 +- .../WiFi/examples/WiFiMultiAdvanced/ci.json | 3 +- libraries/WiFi/examples/WiFiScan/ci.json | 3 +- libraries/WiFi/examples/WiFiScanAsync/ci.json | 3 +- .../WiFi/examples/WiFiScanDualAntenna/ci.json | 3 +- libraries/WiFi/examples/WiFiScanTime/ci.json | 3 +- .../WiFi/examples/WiFiSmartConfig/ci.json | 3 +- .../WiFi/examples/WiFiTelnetToSerial/ci.json | 3 +- libraries/WiFi/examples/WiFiUDPClient/ci.json | 3 +- libraries/WiFiProv/examples/WiFiProv/ci.json | 3 +- package/package_esp32_index.template.json | 56 +- platform.txt | 11 +- tools/get.exe | Bin 6930008 -> 6943192 bytes tools/get.py | 8 + tools/platformio-build.py | 2 +- 169 files changed, 1079 insertions(+), 706 deletions(-) diff --git a/.github/scripts/on-push.sh b/.github/scripts/on-push.sh index 08ff505f1c0..73d9eeee398 100755 --- a/.github/scripts/on-push.sh +++ b/.github/scripts/on-push.sh @@ -91,6 +91,7 @@ if [ "$BUILD_PIO" -eq 0 ]; then fi #build sketches for different targets + build "esp32p4" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32" build "esp32s3" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32" build "esp32s2" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32" build "esp32c3" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32" diff --git a/.github/scripts/sketch_utils.sh b/.github/scripts/sketch_utils.sh index 813f61210cd..5af47dcb138 100755 --- a/.github/scripts/sketch_utils.sh +++ b/.github/scripts/sketch_utils.sh @@ -89,6 +89,7 @@ function build_sketch(){ # build_sketch [ex esp32c3_opts="PartitionScheme=huge_app,FlashMode=dio" esp32c6_opts="PartitionScheme=huge_app,FlashMode=dio" esp32h2_opts="PartitionScheme=huge_app,FlashMode=dio" + esp32p4_opts="PartitionScheme=huge_app,FlashMode=dio" # Select the common part of the FQBN based on the target. The rest will be # appended depending on the passed options. @@ -112,6 +113,9 @@ function build_sketch(){ # build_sketch [ex "esp32h2") fqbn="espressif:esp32:esp32h2:${options:-$esp32h2_opts}" ;; + "esp32p4") + fqbn="espressif:esp32:esp32p4:${options:-$esp32p4_opts}" + ;; esac # Make it look like a JSON array. diff --git a/.github/workflows/lib.yml b/.github/workflows/lib.yml index 894df61f4fd..7a7b863095d 100644 --- a/.github/workflows/lib.yml +++ b/.github/workflows/lib.yml @@ -42,6 +42,7 @@ jobs: - esp32s3 - esp32c6 - esp32h2 + - esp32p4 include: - target: esp32 @@ -56,6 +57,8 @@ jobs: fqbn: espressif:esp32:esp32c6 - target: esp32h2 fqbn: espressif:esp32:esp32h2 + - target: esp32p4 + fqbn: espressif:esp32:esp32p4 steps: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index d5c12c6d3e9..8d25b1a234d 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -233,7 +233,7 @@ jobs: # https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html # for details. idf_ver: ["release-v5.3"] - idf_target: ["esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2"] + idf_target: ["esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4"] container: espressif/idf:${{ matrix.idf_ver }} steps: - name: Check out arduino-esp32 as a component diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 26de19d8f10..1ae748923b5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -88,7 +88,7 @@ jobs: strategy: matrix: type: ${{ fromJson(needs.gen-matrix.outputs.build-types) }} - chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'] + chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32p4'] with: type: ${{ matrix.type }} chip: ${{ matrix.chip }} @@ -105,7 +105,7 @@ jobs: fail-fast: false matrix: type: ${{ fromJson(needs.gen-matrix.outputs.hw-types) }} - chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'] + chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32p4'] with: type: ${{ matrix.type }} chip: ${{ matrix.chip }} diff --git a/.github/workflows/tests_wokwi.yml b/.github/workflows/tests_wokwi.yml index f016cad25e0..14f85ee606e 100644 --- a/.github/workflows/tests_wokwi.yml +++ b/.github/workflows/tests_wokwi.yml @@ -165,7 +165,7 @@ jobs: fail-fast: false matrix: type: ['validation'] - chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'] + chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32p4'] steps: - name: Report pending uses: actions/github-script@v7 diff --git a/README.md b/README.md index ee1880b8d05..d3dca34aafe 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ Here are the ESP32 series supported by the Arduino-ESP32 project: | ESP32-S3 | Yes | Yes | [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) | | ESP32-C6 | Yes | Yes | [ESP32-C6](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) | | ESP32-H2 | Yes | Yes | [ESP32-H2](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) | +| ESP32-P4 | No | No | [ESP32-P4](https://www.espressif.com/sites/default/files/documentation/esp32-p4_datasheet_en.pdf) | > [!NOTE] > ESP32-C2 is also supported by Arduino-ESP32 but requires rebuilding the static libraries. This is not trivial and requires a good understanding of the ESP-IDF diff --git a/boards.txt b/boards.txt index ad47e0df455..f95cf4c21d3 100644 --- a/boards.txt +++ b/boards.txt @@ -163,7 +163,6 @@ esp32c2.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## esp32p4.name=ESP32P4 Dev Module -esp32p4.hide=true esp32p4.bootloader.tool=esptool_py esp32p4.bootloader.tool.default=esptool_py @@ -188,10 +187,10 @@ esp32p4.build.mcu=esp32p4 esp32p4.build.core=esp32 esp32p4.build.variant=esp32p4 esp32p4.build.board=ESP32P4_DEV -esp32p4.build.bootloader_addr=0x0 +esp32p4.build.bootloader_addr=0x2000 esp32p4.build.cdc_on_boot=0 -esp32p4.build.f_cpu=400000000L +esp32p4.build.f_cpu=360000000L esp32p4.build.flash_size=4MB esp32p4.build.flash_freq=80m esp32p4.build.img_freq=80m @@ -203,6 +202,25 @@ esp32p4.build.defines= ## IDE 2.0 Seems to not update the value esp32p4.menu.JTAGAdapter.default=Disabled esp32p4.menu.JTAGAdapter.default.build.copy_jtag_files=0 +esp32p4.menu.JTAGAdapter.builtin=Integrated USB JTAG +esp32p4.menu.JTAGAdapter.builtin.build.openocdscript=esp32p4-builtin.cfg +esp32p4.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +esp32p4.menu.JTAGAdapter.external=FTDI Adapter +esp32p4.menu.JTAGAdapter.external.build.openocdscript=esp32p4-ftdi.cfg +esp32p4.menu.JTAGAdapter.external.build.copy_jtag_files=1 +esp32p4.menu.JTAGAdapter.bridge=ESP USB Bridge +esp32p4.menu.JTAGAdapter.bridge.build.openocdscript=esp32p4-bridge.cfg +esp32p4.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +esp32p4.menu.CDCOnBoot.default=Disabled +esp32p4.menu.CDCOnBoot.default.build.cdc_on_boot=0 +esp32p4.menu.CDCOnBoot.cdc=Enabled +esp32p4.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +esp32p4.menu.PSRAM.disabled=Disabled +esp32p4.menu.PSRAM.disabled.build.defines= +esp32p4.menu.PSRAM.enabled=Enabled +esp32p4.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM esp32p4.menu.CDCOnBoot.default=Disabled esp32p4.menu.CDCOnBoot.default.build.cdc_on_boot=0 @@ -211,20 +229,87 @@ esp32p4.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 esp32p4.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) esp32p4.menu.PartitionScheme.default.build.partitions=default +esp32p4.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +esp32p4.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +esp32p4.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +esp32p4.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +esp32p4.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +esp32p4.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +esp32p4.menu.PartitionScheme.minimal.build.partitions=minimal esp32p4.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) esp32p4.menu.PartitionScheme.no_fs.build.partitions=no_fs esp32p4.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +esp32p4.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +esp32p4.menu.PartitionScheme.no_ota.build.partitions=no_ota +esp32p4.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +esp32p4.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +esp32p4.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +esp32p4.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +esp32p4.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +esp32p4.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +esp32p4.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +esp32p4.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +esp32p4.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +esp32p4.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 esp32p4.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) esp32p4.menu.PartitionScheme.huge_app.build.partitions=huge_app esp32p4.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +esp32p4.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +esp32p4.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +esp32p4.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +esp32p4.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +esp32p4.menu.PartitionScheme.fatflash.build.partitions=ffat +esp32p4.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +esp32p4.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +esp32p4.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +esp32p4.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 esp32p4.menu.PartitionScheme.custom=Custom esp32p4.menu.PartitionScheme.custom.build.partitions= esp32p4.menu.PartitionScheme.custom.upload.maximum_size=16777216 +## From https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/kconfig.html#config-esp-default-cpu-freq-mhz +esp32p4.menu.CPUFreq.360=360MHz +esp32p4.menu.CPUFreq.360.build.f_cpu=360000000L +esp32p4.menu.CPUFreq.40=40MHz +esp32p4.menu.CPUFreq.40.build.f_cpu=40000000L + +esp32p4.menu.FlashMode.qio=QIO +esp32p4.menu.FlashMode.qio.build.flash_mode=dio +esp32p4.menu.FlashMode.qio.build.boot=qio +esp32p4.menu.FlashMode.dio=DIO +esp32p4.menu.FlashMode.dio.build.flash_mode=dio +esp32p4.menu.FlashMode.dio.build.boot=dio + +esp32p4.menu.FlashFreq.80=80MHz +esp32p4.menu.FlashFreq.80.build.flash_freq=80m +esp32p4.menu.FlashFreq.40=40MHz +esp32p4.menu.FlashFreq.40.build.flash_freq=40m + +esp32p4.menu.FlashSize.4M=4MB (32Mb) +esp32p4.menu.FlashSize.4M.build.flash_size=4MB +esp32p4.menu.FlashSize.8M=8MB (64Mb) +esp32p4.menu.FlashSize.8M.build.flash_size=8MB +esp32p4.menu.FlashSize.8M.build.partitions=default_8MB +esp32p4.menu.FlashSize.2M=2MB (16Mb) +esp32p4.menu.FlashSize.2M.build.flash_size=2MB +esp32p4.menu.FlashSize.2M.build.partitions=minimal +esp32p4.menu.FlashSize.16M=16MB (128Mb) +esp32p4.menu.FlashSize.16M.build.flash_size=16MB + esp32p4.menu.UploadSpeed.921600=921600 esp32p4.menu.UploadSpeed.921600.upload.speed=921600 esp32p4.menu.UploadSpeed.115200=115200 esp32p4.menu.UploadSpeed.115200.upload.speed=115200 +esp32p4.menu.UploadSpeed.256000.windows=256000 +esp32p4.menu.UploadSpeed.256000.upload.speed=256000 +esp32p4.menu.UploadSpeed.230400.windows.upload.speed=256000 +esp32p4.menu.UploadSpeed.230400=230400 +esp32p4.menu.UploadSpeed.230400.upload.speed=230400 +esp32p4.menu.UploadSpeed.460800.linux=460800 +esp32p4.menu.UploadSpeed.460800.macosx=460800 +esp32p4.menu.UploadSpeed.460800.upload.speed=460800 +esp32p4.menu.UploadSpeed.512000.windows=512000 +esp32p4.menu.UploadSpeed.512000.upload.speed=512000 esp32p4.menu.DebugLevel.none=None esp32p4.menu.DebugLevel.none.build.code_debug=0 diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 483e888f64f..6a6ed11e463 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -60,6 +60,9 @@ extern "C" { #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/spi_flash.h" #define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32h2 is located at 0x0000 +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/spi_flash.h" +#define ESP_FLASH_IMAGE_BASE 0x2000 // Esp32p4 is located at 0x2000 #else #error Target CONFIG_IDF_TARGET is not supported #endif @@ -335,6 +338,8 @@ uint32_t EspClass::getFlashChipSpeed(void) { return magicFlashChipSpeed(fhdr.spi_speed); } +// FIXME for P4 +#if !defined(CONFIG_IDF_TARGET_ESP32P4) FlashMode_t EspClass::getFlashChipMode(void) { #if CONFIG_IDF_TARGET_ESP32S2 uint32_t spi_ctrl = REG_READ(PERIPHS_SPI_FLASH_CTRL); @@ -361,6 +366,7 @@ FlashMode_t EspClass::getFlashChipMode(void) { } return (FM_DOUT); } +#endif // if !defined(CONFIG_IDF_TARGET_ESP32P4) uint32_t EspClass::magicFlashChipSize(uint8_t byte) { /* diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 23a8823dff7..fc5dd92440d 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -125,6 +125,8 @@ typedef enum { #define SOC_RX0 (gpio_num_t)17 #elif CONFIG_IDF_TARGET_ESP32H2 #define SOC_RX0 (gpio_num_t)23 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define SOC_RX0 (gpio_num_t)38 #endif #endif @@ -141,6 +143,8 @@ typedef enum { #define SOC_TX0 (gpio_num_t)16 #elif CONFIG_IDF_TARGET_ESP32H2 #define SOC_TX0 (gpio_num_t)24 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define SOC_TX0 (gpio_num_t)37 #endif #endif @@ -162,6 +166,8 @@ typedef enum { #define RX1 (gpio_num_t)4 #elif CONFIG_IDF_TARGET_ESP32H2 #define RX1 (gpio_num_t)0 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define RX1 (gpio_num_t)11 #endif #endif @@ -180,6 +186,8 @@ typedef enum { #define TX1 (gpio_num_t)5 #elif CONFIG_IDF_TARGET_ESP32H2 #define TX1 (gpio_num_t)1 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define TX1 (gpio_num_t)10 #endif #endif #endif /* SOC_UART_HP_NUM > 1 */ @@ -192,6 +200,8 @@ typedef enum { #define RX2 (gpio_num_t)4 #elif CONFIG_IDF_TARGET_ESP32S3 #define RX2 (gpio_num_t)19 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define RX2 (gpio_num_t)15 #endif #endif @@ -200,6 +210,8 @@ typedef enum { #define TX2 (gpio_num_t)25 #elif CONFIG_IDF_TARGET_ESP32S3 #define TX2 (gpio_num_t)20 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define TX2 (gpio_num_t)14 #endif #endif #endif /* SOC_UART_HP_NUM > 2 */ diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index 239ae3e97c9..daafef3cab9 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -64,6 +64,9 @@ static void printPkgVersion(void) { #elif CONFIG_IDF_TARGET_ESP32H2 uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SYS_4_REG, EFUSE_PKG_VERSION); chip_report_printf("%lu", pkg_ver); +#elif CONFIG_IDF_TARGET_ESP32P4 + uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SYS_2_REG, EFUSE_PKG_VERSION); + chip_report_printf("%lu", pkg_ver); #else chip_report_printf("Unknown"); #endif @@ -84,6 +87,7 @@ static void printChipInfo(void) { case CHIP_ESP32C3: chip_report_printf("ESP32-C3\n"); break; case CHIP_ESP32C6: chip_report_printf("ESP32-C6\n"); break; case CHIP_ESP32H2: chip_report_printf("ESP32-H2\n"); break; + case CHIP_ESP32P4: chip_report_printf("ESP32-P4\n"); break; default: chip_report_printf("Unknown %d\n", info.model); break; } printPkgVersion(); @@ -105,6 +109,8 @@ static void printChipInfo(void) { static void printFlashInfo(void) { #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 #define ESP_FLASH_IMAGE_BASE 0x1000 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define ESP_FLASH_IMAGE_BASE 0x2000 #else #define ESP_FLASH_IMAGE_BASE 0x0000 #endif diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c index ee9cd02a623..c7cc1f5d556 100644 --- a/cores/esp32/esp32-hal-adc.c +++ b/cores/esp32/esp32-hal-adc.c @@ -75,7 +75,7 @@ static bool adcDetachBus(void *pin) { if (err != ESP_OK) { return false; } -#elif !defined(CONFIG_IDF_TARGET_ESP32H2) +#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)) err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); if (err != ESP_OK) { return false; @@ -127,7 +127,7 @@ esp_err_t __analogChannelConfig(adc_bitwidth_t width, adc_attenuation_t atten, i log_e("adc_cali_create_scheme_curve_fitting failed with error: %d", err); return err; } -#elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED +#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED log_d("Deleting ADC_UNIT_%d line cali handle", adc_unit); err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); if (err != ESP_OK) { @@ -310,7 +310,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin) { .bitwidth = __analogWidth, }; err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); -#elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED +#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED adc_cali_line_fitting_config_t cali_config = { .unit_id = adc_unit, .bitwidth = __analogWidth, @@ -379,7 +379,7 @@ static bool adcContinuousDetachBus(void *adc_unit_number) { if (err != ESP_OK) { return false; } -#elif !defined(CONFIG_IDF_TARGET_ESP32H2) +#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)) err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); if (err != ESP_OK) { return false; @@ -552,7 +552,7 @@ bool analogContinuous(const uint8_t pins[], size_t pins_count, uint32_t conversi .bitwidth = __adcContinuousWidth, }; err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); -#elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED +#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED adc_cali_line_fitting_config_t cali_config = { .unit_id = adc_unit, .bitwidth = __adcContinuousWidth, diff --git a/cores/esp32/esp32-hal-cpu.c b/cores/esp32/esp32-hal-cpu.c index 2420dfbeeb0..f0a30b50afc 100644 --- a/cores/esp32/esp32-hal-cpu.c +++ b/cores/esp32/esp32-hal-cpu.c @@ -19,7 +19,7 @@ #include "esp_attr.h" #include "esp_log.h" #include "soc/rtc.h" -#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) #include "soc/rtc_cntl_reg.h" #include "soc/syscon_reg.h" #endif @@ -46,6 +46,8 @@ #include "esp32c6/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/rtc.h" #else #error Target CONFIG_IDF_TARGET is not supported #endif @@ -161,13 +163,13 @@ bool removeApbChangeCallback(void *arg, apb_change_cb_t cb) { } static uint32_t calculateApb(rtc_cpu_freq_config_t *conf) { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 - return APB_CLK_FREQ; -#else +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 if (conf->freq_mhz >= 80) { return 80 * MHZ; } return (conf->source_freq_mhz * MHZ) / conf->div; +#else + return APB_CLK_FREQ; #endif } @@ -177,7 +179,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { rtc_cpu_freq_config_t conf, cconf; uint32_t capb, apb; //Get XTAL Frequency and calculate min CPU MHz -#ifndef CONFIG_IDF_TARGET_ESP32H2 +#if (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)) rtc_xtal_freq_t xtal = rtc_clk_xtal_freq_get(); #endif #if CONFIG_IDF_TARGET_ESP32 @@ -193,7 +195,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { } } #endif -#ifndef CONFIG_IDF_TARGET_ESP32H2 +#if (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)) if (cpu_freq_mhz > xtal && cpu_freq_mhz != 240 && cpu_freq_mhz != 160 && cpu_freq_mhz != 120 && cpu_freq_mhz != 80) { if (xtal >= RTC_XTAL_FREQ_40M) { log_e("Bad frequency: %u MHz! Options are: 240, 160, 120, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal / 2, xtal / 4); @@ -235,7 +237,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { } //Make the frequency change rtc_clk_cpu_freq_set_config_fast(&conf); -#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) if (capb != apb) { //Update REF_TICK (uncomment if REF_TICK is different than 1MHz) //if(conf.freq_mhz < 80){ @@ -248,11 +250,8 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { } #endif //Update FreeRTOS Tick Divisor -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 -#elif CONFIG_IDF_TARGET_ESP32S3 - -#else +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 uint32_t fcpu = (conf.freq_mhz >= 80) ? (conf.freq_mhz * MHZ) : (apb); _xt_tick_divisor = fcpu / XT_TICK_PER_SEC; #endif @@ -263,13 +262,19 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { #ifdef SOC_CLK_APLL_SUPPORTED log_d( "%s: %u / %u = %u Mhz, APB: %u Hz", - (conf.source == RTC_CPU_FREQ_SRC_PLL) ? "PLL" - : ((conf.source == RTC_CPU_FREQ_SRC_APLL) ? "APLL" : ((conf.source == RTC_CPU_FREQ_SRC_XTAL) ? "XTAL" : "8M")), + (conf.source == SOC_CPU_CLK_SRC_PLL) ? "PLL" + : ((conf.source == SOC_CPU_CLK_SRC_APLL) ? "APLL" + : ((conf.source == SOC_CPU_CLK_SRC_XTAL) ? "XTAL" +#ifdef CONFIG_IDF_TARGET_ESP32P4 + : "17.5M"), +#else + : "8M")), +#endif conf.source_freq_mhz, conf.div, conf.freq_mhz, apb ); #else log_d( - "%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == RTC_CPU_FREQ_SRC_PLL) ? "PLL" : ((conf.source == RTC_CPU_FREQ_SRC_XTAL) ? "XTAL" : "17.5M"), + "%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == SOC_CPU_CLK_SRC_PLL) ? "PLL" : ((conf.source == SOC_CPU_CLK_SRC_XTAL) ? "XTAL" : "17.5M"), conf.source_freq_mhz, conf.div, conf.freq_mhz, apb ); #endif diff --git a/cores/esp32/esp32-hal-i2c-slave.c b/cores/esp32/esp32-hal-i2c-slave.c index 5504fd62adf..14da815455b 100644 --- a/cores/esp32/esp32-hal-i2c-slave.c +++ b/cores/esp32/esp32-hal-i2c-slave.c @@ -41,14 +41,32 @@ #include "esp_intr_alloc.h" #include "soc/i2c_reg.h" #include "soc/i2c_struct.h" +#include "soc/periph_defs.h" #include "hal/i2c_ll.h" #include "hal/clk_gate_ll.h" #include "esp32-hal-log.h" #include "esp32-hal-i2c-slave.h" #include "esp32-hal-periman.h" +#include "esp_private/periph_ctrl.h" + +#if SOC_PERIPH_CLK_CTRL_SHARED +#define I2C_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2C_CLOCK_SRC_ATOMIC() +#endif + +#if !SOC_RCC_IS_INDEPENDENT +#define I2C_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2C_RCC_ATOMIC() +#endif #define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer +#ifdef CONFIG_IDF_TARGET_ESP32P4 +#define I2C_SCL_IDX(p) ((p == 0) ? I2C0_SCL_PAD_OUT_IDX : ((p == 1) ? I2C1_SCL_PAD_OUT_IDX : 0)) +#define I2C_SDA_IDX(p) ((p == 0) ? I2C0_SDA_PAD_OUT_IDX : ((p == 1) ? I2C1_SDA_PAD_OUT_IDX : 0)) +#else #if SOC_HP_I2C_NUM > 1 #define I2C_SCL_IDX(p) ((p == 0) ? I2CEXT0_SCL_OUT_IDX : ((p == 1) ? I2CEXT1_SCL_OUT_IDX : 0)) #define I2C_SDA_IDX(p) ((p == 0) ? I2CEXT0_SDA_OUT_IDX : ((p == 1) ? I2CEXT1_SDA_OUT_IDX : 0)) @@ -56,6 +74,7 @@ #define I2C_SCL_IDX(p) I2CEXT0_SCL_OUT_IDX #define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX #endif +#endif // ifdef CONFIG_IDF_TARGET_ESP32P4 #if CONFIG_IDF_TARGET_ESP32 #define I2C_TXFIFO_WM_INT_ENA I2C_TXFIFO_EMPTY_INT_ENA @@ -173,19 +192,19 @@ static inline void i2c_ll_stretch_clr(i2c_dev_t *hw) { } static inline bool i2c_ll_slave_addressed(i2c_dev_t *hw) { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 - return hw->sr.slave_addressed; -#else +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 return hw->status_reg.slave_addressed; +#else + return hw->sr.slave_addressed; #endif } static inline bool i2c_ll_slave_rw(i2c_dev_t *hw) //not exposed by hal_ll { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 - return hw->sr.slave_rw; -#else +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 return hw->status_reg.slave_rw; +#else + return hw->sr.slave_rw; #endif } @@ -306,7 +325,7 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency = 100000L; } frequency = (frequency * 5) / 4; - +#if !defined(CONFIG_IDF_TARGET_ESP32P4) if (i2c->num == 0) { periph_ll_enable_clk_clear_rst(PERIPH_I2C0_MODULE); #if SOC_HP_I2C_NUM > 1 @@ -314,6 +333,7 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t periph_ll_enable_clk_clear_rst(PERIPH_I2C1_MODULE); #endif } +#endif // !defined(CONFIG_IDF_TARGET_ESP32P4) i2c_ll_slave_init(i2c->dev); i2c_ll_slave_set_fifo_mode(i2c->dev, true); @@ -341,145 +361,155 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t if (!i2c->intr_handle) { uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED; +#if !defined(CONFIG_IDF_TARGET_ESP32P4) if (i2c->num == 0) { ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); #if SOC_HP_I2C_NUM > 1 } else { ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); #endif - } +#endif // !defined(CONFIG_IDF_TARGET_ESP32P4) +#ifdef CONFIG_IDF_TARGET_ESP32P4 + if (i2c->num == 0) { + ret = esp_intr_alloc(ETS_I2C0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); +#if SOC_I2C_NUM > 1 + } else { + ret = esp_intr_alloc(ETS_I2C1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); +#endif +#endif // #ifdef CONFIG_IDF_TARGET_ESP32P4 + } - if (ret != ESP_OK) { - log_e("install interrupt handler Failed=%d", ret); - goto fail; + if (ret != ESP_OK) { + log_e("install interrupt handler Failed=%d", ret); + goto fail; + } } - } - i2c_ll_txfifo_rst(i2c->dev); - i2c_ll_rxfifo_rst(i2c->dev); - i2c_ll_slave_enable_rx_it(i2c->dev); - i2c_ll_set_stretch(i2c->dev, 0x3FF); - i2c_ll_update(i2c->dev); - if (!perimanSetPinBus(sda, ESP32_BUS_TYPE_I2C_SLAVE_SDA, (void *)(i2c->num + 1), i2c->num, -1) - || !perimanSetPinBus(scl, ESP32_BUS_TYPE_I2C_SLAVE_SCL, (void *)(i2c->num + 1), i2c->num, -1)) { - i2cSlaveDetachBus((void *)(i2c->num + 1)); - ret = ESP_FAIL; - } - I2C_SLAVE_MUTEX_UNLOCK(); - return ret; + i2c_ll_txfifo_rst(i2c->dev); + i2c_ll_rxfifo_rst(i2c->dev); + i2c_ll_slave_enable_rx_it(i2c->dev); + i2c_ll_set_stretch(i2c->dev, 0x3FF); + i2c_ll_update(i2c->dev); + if (!perimanSetPinBus(sda, ESP32_BUS_TYPE_I2C_SLAVE_SDA, (void *)(i2c->num + 1), i2c->num, -1) + || !perimanSetPinBus(scl, ESP32_BUS_TYPE_I2C_SLAVE_SCL, (void *)(i2c->num + 1), i2c->num, -1)) { + i2cSlaveDetachBus((void *)(i2c->num + 1)); + ret = ESP_FAIL; + } + I2C_SLAVE_MUTEX_UNLOCK(); + return ret; fail: - i2c_slave_free_resources(i2c); - I2C_SLAVE_MUTEX_UNLOCK(); - return ret; -} - -esp_err_t i2cSlaveDeinit(uint8_t num) { - if (num >= SOC_HP_I2C_NUM) { - log_e("Invalid port num: %u", num); - return ESP_ERR_INVALID_ARG; + i2c_slave_free_resources(i2c); + I2C_SLAVE_MUTEX_UNLOCK(); + return ret; } - i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; + esp_err_t i2cSlaveDeinit(uint8_t num) { + if (num >= SOC_HP_I2C_NUM) { + log_e("Invalid port num: %u", num); + return ESP_ERR_INVALID_ARG; + } + + i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; #if !CONFIG_DISABLE_HAL_LOCKS - if (!i2c->lock) { - log_e("Lock is not initialized! Did you call i2c_slave_init()?"); - return ESP_ERR_NO_MEM; - } + if (!i2c->lock) { + log_e("Lock is not initialized! Did you call i2c_slave_init()?"); + return ESP_ERR_NO_MEM; + } #endif - I2C_SLAVE_MUTEX_LOCK(); - int scl = i2c->scl; - int sda = i2c->sda; - i2c_slave_free_resources(i2c); - perimanClearPinBus(scl); - perimanClearPinBus(sda); - I2C_SLAVE_MUTEX_UNLOCK(); - return ESP_OK; -} - -size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { - if (num >= SOC_HP_I2C_NUM) { - log_e("Invalid port num: %u", num); - return 0; - } - uint32_t to_queue = 0, to_fifo = 0; - i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; + I2C_SLAVE_MUTEX_LOCK(); + int scl = i2c->scl; + int sda = i2c->sda; + i2c_slave_free_resources(i2c); + perimanClearPinBus(scl); + perimanClearPinBus(sda); + I2C_SLAVE_MUTEX_UNLOCK(); + return ESP_OK; + } + + size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { + if (num >= SOC_HP_I2C_NUM) { + log_e("Invalid port num: %u", num); + return 0; + } + uint32_t to_queue = 0, to_fifo = 0; + i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; #if !CONFIG_DISABLE_HAL_LOCKS - if (!i2c->lock) { - log_e("Lock is not initialized! Did you call i2c_slave_init()?"); - return ESP_ERR_NO_MEM; - } + if (!i2c->lock) { + log_e("Lock is not initialized! Did you call i2c_slave_init()?"); + return ESP_ERR_NO_MEM; + } #endif - if (!i2c->tx_queue) { - return 0; - } - I2C_SLAVE_MUTEX_LOCK(); + if (!i2c->tx_queue) { + return 0; + } + I2C_SLAVE_MUTEX_LOCK(); #if CONFIG_IDF_TARGET_ESP32 - i2c_ll_slave_disable_tx_it(i2c->dev); - uint32_t txfifo_len = 0; - i2c_ll_get_txfifo_len(i2c->dev, &txfifo_len); - if (txfifo_len < SOC_I2C_FIFO_LEN) { - i2c_ll_txfifo_rst(i2c->dev); - } + i2c_ll_slave_disable_tx_it(i2c->dev); + uint32_t txfifo_len = 0; + i2c_ll_get_txfifo_len(i2c->dev, &txfifo_len); + if (txfifo_len < SOC_I2C_FIFO_LEN) { + i2c_ll_txfifo_rst(i2c->dev); + } #endif - i2c_ll_get_txfifo_len(i2c->dev, &to_fifo); - if (to_fifo) { - if (len < to_fifo) { - to_fifo = len; - } - i2c_ll_write_txfifo(i2c->dev, (uint8_t *)buf, to_fifo); - buf += to_fifo; - len -= to_fifo; - //reset tx_queue - xQueueReset(i2c->tx_queue); - //write the rest of the bytes to the queue - if (len) { - to_queue = uxQueueSpacesAvailable(i2c->tx_queue); - if (len < to_queue) { - to_queue = len; + i2c_ll_get_txfifo_len(i2c->dev, &to_fifo); + if (to_fifo) { + if (len < to_fifo) { + to_fifo = len; } - for (size_t i = 0; i < to_queue; i++) { - if (xQueueSend(i2c->tx_queue, &buf[i], timeout_ms / portTICK_PERIOD_MS) != pdTRUE) { - xQueueReset(i2c->tx_queue); - to_queue = 0; - break; + i2c_ll_write_txfifo(i2c->dev, (uint8_t *)buf, to_fifo); + buf += to_fifo; + len -= to_fifo; + //reset tx_queue + xQueueReset(i2c->tx_queue); + //write the rest of the bytes to the queue + if (len) { + to_queue = uxQueueSpacesAvailable(i2c->tx_queue); + if (len < to_queue) { + to_queue = len; + } + for (size_t i = 0; i < to_queue; i++) { + if (xQueueSend(i2c->tx_queue, &buf[i], timeout_ms / portTICK_PERIOD_MS) != pdTRUE) { + xQueueReset(i2c->tx_queue); + to_queue = 0; + break; + } + } + //no need to enable TX_EMPTY if tx_queue is empty + if (to_queue) { + i2c_ll_slave_enable_tx_it(i2c->dev); } - } - //no need to enable TX_EMPTY if tx_queue is empty - if (to_queue) { - i2c_ll_slave_enable_tx_it(i2c->dev); } } + I2C_SLAVE_MUTEX_UNLOCK(); + return to_queue + to_fifo; } - I2C_SLAVE_MUTEX_UNLOCK(); - return to_queue + to_fifo; -} -//===================================================================================================================== -//-------------------------------------- Private Functions ------------------------------------------------------------ -//===================================================================================================================== + //===================================================================================================================== + //-------------------------------------- Private Functions ------------------------------------------------------------ + //===================================================================================================================== -static void i2c_slave_free_resources(i2c_slave_struct_t *i2c) { - i2c_slave_detach_gpio(i2c); - i2c_ll_set_slave_addr(i2c->dev, 0, false); - i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); - i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK); + static void i2c_slave_free_resources(i2c_slave_struct_t * i2c) { + i2c_slave_detach_gpio(i2c); + i2c_ll_set_slave_addr(i2c->dev, 0, false); + i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); + i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK); - if (i2c->intr_handle) { - esp_intr_free(i2c->intr_handle); - i2c->intr_handle = NULL; - } + if (i2c->intr_handle) { + esp_intr_free(i2c->intr_handle); + i2c->intr_handle = NULL; + } - if (i2c->task_handle) { - vTaskDelete(i2c->task_handle); - i2c->task_handle = NULL; - } + if (i2c->task_handle) { + vTaskDelete(i2c->task_handle); + i2c->task_handle = NULL; + } #if I2C_SLAVE_USE_RX_QUEUE - if (i2c->rx_queue) { - vQueueDelete(i2c->rx_queue); - i2c->rx_queue = NULL; - } + if (i2c->rx_queue) { + vQueueDelete(i2c->rx_queue); + i2c->rx_queue = NULL; + } #else if (i2c->rx_ring_buf) { vRingbufferDelete(i2c->rx_ring_buf); @@ -487,198 +517,202 @@ static void i2c_slave_free_resources(i2c_slave_struct_t *i2c) { } #endif - if (i2c->tx_queue) { - vQueueDelete(i2c->tx_queue); - i2c->tx_queue = NULL; - } - - if (i2c->event_queue) { - vQueueDelete(i2c->event_queue); - i2c->event_queue = NULL; - } + if (i2c->tx_queue) { + vQueueDelete(i2c->tx_queue); + i2c->tx_queue = NULL; + } - i2c->rx_data_count = 0; -} + if (i2c->event_queue) { + vQueueDelete(i2c->event_queue); + i2c->event_queue = NULL; + } -static bool i2c_slave_set_frequency(i2c_slave_struct_t *i2c, uint32_t clk_speed) { - if (i2c == NULL) { - log_e("no control buffer"); - return false; - } - if (clk_speed > 1100000UL) { - clk_speed = 1100000UL; + i2c->rx_data_count = 0; } - // Adjust Fifo thresholds based on frequency - uint32_t a = (clk_speed / 50000L) + 2; - log_d("Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d", SOC_I2C_FIFO_LEN - a, a); + static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed) { + if (i2c == NULL) { + log_e("no control buffer"); + return false; + } + if (clk_speed > 1100000UL) { + clk_speed = 1100000UL; + } + + // Adjust Fifo thresholds based on frequency + uint32_t a = (clk_speed / 50000L) + 2; + log_d("Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d", SOC_I2C_FIFO_LEN - a, a); - i2c_hal_clk_config_t clk_cal; + i2c_hal_clk_config_t clk_cal; #if SOC_I2C_SUPPORT_APB - i2c_ll_master_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal); - i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_APB); /*!< I2C source clock from APB, 80M*/ + i2c_ll_master_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal); + I2C_CLOCK_SRC_ATOMIC() { + i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_APB); /*!< I2C source clock from APB, 80M*/ + } #elif SOC_I2C_SUPPORT_XTAL i2c_ll_master_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal); - i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_XTAL); /*!< I2C source clock from XTAL, 40M */ + I2C_CLOCK_SRC_ATOMIC() { + i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_XTAL); /*!< I2C source clock from XTAL, 40M */ + } #endif - i2c_ll_set_txfifo_empty_thr(i2c->dev, a); - i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a); - i2c_ll_master_set_bus_timing(i2c->dev, &clk_cal); - i2c_ll_master_set_filter(i2c->dev, 3); - return true; -} + i2c_ll_set_txfifo_empty_thr(i2c->dev, a); + i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a); + i2c_ll_master_set_bus_timing(i2c->dev, &clk_cal); + i2c_ll_master_set_filter(i2c->dev, 3); + return true; + } -static void i2c_slave_delay_us(uint64_t us) { - uint64_t m = esp_timer_get_time(); - if (us) { - uint64_t e = (m + us); - if (m > e) { //overflow - while ((uint64_t)esp_timer_get_time() > e); + static void i2c_slave_delay_us(uint64_t us) { + uint64_t m = esp_timer_get_time(); + if (us) { + uint64_t e = (m + us); + if (m > e) { //overflow + while ((uint64_t)esp_timer_get_time() > e); + } + while ((uint64_t)esp_timer_get_time() < e); } - while ((uint64_t)esp_timer_get_time() < e); } -} -static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode) { - gpio_config_t conf = { - .pin_bit_mask = 1LL << pin, .mode = mode, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE - }; - gpio_config(&conf); -} + static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode) { + gpio_config_t conf = { + .pin_bit_mask = 1LL << pin, .mode = mode, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&conf); + } -static bool i2c_slave_check_line_state(int8_t sda, int8_t scl) { - if (sda < 0 || scl < 0) { - return false; //return false since there is nothing to do - } - // if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles - gpio_set_level(sda, 1); - gpio_set_level(scl, 1); - i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); - i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); - gpio_set_level(scl, 1); - - if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state - log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl)); - for (uint8_t a = 0; a < 9; a++) { - i2c_slave_delay_us(5); - if (gpio_get_level(sda) && gpio_get_level(scl)) { // bus recovered - log_w("Recovered after %d Cycles", a); - gpio_set_level(sda, 0); // start + static bool i2c_slave_check_line_state(int8_t sda, int8_t scl) { + if (sda < 0 || scl < 0) { + return false; //return false since there is nothing to do + } + // if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles + gpio_set_level(sda, 1); + gpio_set_level(scl, 1); + i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); + i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); + gpio_set_level(scl, 1); + + if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state + log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl)); + for (uint8_t a = 0; a < 9; a++) { i2c_slave_delay_us(5); - for (uint8_t a = 0; a < 9; a++) { - gpio_set_level(scl, 1); + if (gpio_get_level(sda) && gpio_get_level(scl)) { // bus recovered + log_w("Recovered after %d Cycles", a); + gpio_set_level(sda, 0); // start i2c_slave_delay_us(5); - gpio_set_level(scl, 0); + for (uint8_t a = 0; a < 9; a++) { + gpio_set_level(scl, 1); + i2c_slave_delay_us(5); + gpio_set_level(scl, 0); + i2c_slave_delay_us(5); + } + gpio_set_level(scl, 1); i2c_slave_delay_us(5); + gpio_set_level(sda, 1); // stop + break; } - gpio_set_level(scl, 1); + gpio_set_level(scl, 0); i2c_slave_delay_us(5); - gpio_set_level(sda, 1); // stop - break; + gpio_set_level(scl, 1); } - gpio_set_level(scl, 0); - i2c_slave_delay_us(5); - gpio_set_level(scl, 1); } - } - - if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state - log_e("Bus Invalid State, Can't init sda=%d, scl=%d", gpio_get_level(sda), gpio_get_level(scl)); - return false; // bus is busy - } - return true; -} -static bool i2c_slave_attach_gpio(i2c_slave_struct_t *i2c, int8_t sda, int8_t scl) { - if (i2c == NULL) { - log_e("no control block"); - return false; + if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state + log_e("Bus Invalid State, Can't init sda=%d, scl=%d", gpio_get_level(sda), gpio_get_level(scl)); + return false; // bus is busy + } + return true; } - if ((sda < 0) || (scl < 0)) { - log_e("bad pins sda=%d, scl=%d", sda, scl); - return false; - } + static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl) { + if (i2c == NULL) { + log_e("no control block"); + return false; + } - i2c->scl = scl; - gpio_set_level(scl, 1); - i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT_OUTPUT_OD); - gpio_matrix_out(scl, I2C_SCL_IDX(i2c->num), false, false); - gpio_matrix_in(scl, I2C_SCL_IDX(i2c->num), false); + if ((sda < 0) || (scl < 0)) { + log_e("bad pins sda=%d, scl=%d", sda, scl); + return false; + } - i2c->sda = sda; - gpio_set_level(sda, 1); - i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT_OUTPUT_OD); - gpio_matrix_out(sda, I2C_SDA_IDX(i2c->num), false, false); - gpio_matrix_in(sda, I2C_SDA_IDX(i2c->num), false); + i2c->scl = scl; + gpio_set_level(scl, 1); + i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_matrix_out(scl, I2C_SCL_IDX(i2c->num), false, false); + gpio_matrix_in(scl, I2C_SCL_IDX(i2c->num), false); - return true; -} + i2c->sda = sda; + gpio_set_level(sda, 1); + i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_matrix_out(sda, I2C_SDA_IDX(i2c->num), false, false); + gpio_matrix_in(sda, I2C_SDA_IDX(i2c->num), false); -static bool i2c_slave_detach_gpio(i2c_slave_struct_t *i2c) { - if (i2c == NULL) { - log_e("no control Block"); - return false; - } - if (i2c->scl >= 0) { - gpio_matrix_out(i2c->scl, 0x100, false, false); - gpio_matrix_in(0x30, I2C_SCL_IDX(i2c->num), false); - i2c_slave_gpio_mode(i2c->scl, GPIO_MODE_INPUT); - i2c->scl = -1; // un attached - } - if (i2c->sda >= 0) { - gpio_matrix_out(i2c->sda, 0x100, false, false); - gpio_matrix_in(0x30, I2C_SDA_IDX(i2c->num), false); - i2c_slave_gpio_mode(i2c->sda, GPIO_MODE_INPUT); - i2c->sda = -1; // un attached + return true; } - return true; -} -static bool i2c_slave_send_event(i2c_slave_struct_t *i2c, i2c_slave_queue_event_t *event) { - bool pxHigherPriorityTaskWoken = false; - if (i2c->event_queue) { - if (xQueueSendFromISR(i2c->event_queue, event, (BaseType_t *const)&pxHigherPriorityTaskWoken) != pdTRUE) { - //log_e("event_queue_full"); + static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c) { + if (i2c == NULL) { + log_e("no control Block"); + return false; + } + if (i2c->scl >= 0) { + gpio_matrix_out(i2c->scl, 0x100, false, false); + gpio_matrix_in(0x30, I2C_SCL_IDX(i2c->num), false); + i2c_slave_gpio_mode(i2c->scl, GPIO_MODE_INPUT); + i2c->scl = -1; // un attached } + if (i2c->sda >= 0) { + gpio_matrix_out(i2c->sda, 0x100, false, false); + gpio_matrix_in(0x30, I2C_SDA_IDX(i2c->num), false); + i2c_slave_gpio_mode(i2c->sda, GPIO_MODE_INPUT); + i2c->sda = -1; // un attached + } + return true; } - return pxHigherPriorityTaskWoken; -} -static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t *i2c) { - bool pxHigherPriorityTaskWoken = false; - uint32_t d = 0, moveCnt = 0; - i2c_ll_get_txfifo_len(i2c->dev, &moveCnt); - while (moveCnt > 0) { // read tx queue until Fifo is full or queue is empty - if (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) == pdTRUE) { - i2c_ll_write_txfifo(i2c->dev, (uint8_t *)&d, 1); - moveCnt--; - } else { - i2c_ll_slave_disable_tx_it(i2c->dev); - break; + static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t * event) { + bool pxHigherPriorityTaskWoken = false; + if (i2c->event_queue) { + if (xQueueSendFromISR(i2c->event_queue, event, (BaseType_t *const)&pxHigherPriorityTaskWoken) != pdTRUE) { + //log_e("event_queue_full"); + } + } + return pxHigherPriorityTaskWoken; + } + + static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c) { + bool pxHigherPriorityTaskWoken = false; + uint32_t d = 0, moveCnt = 0; + i2c_ll_get_txfifo_len(i2c->dev, &moveCnt); + while (moveCnt > 0) { // read tx queue until Fifo is full or queue is empty + if (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) == pdTRUE) { + i2c_ll_write_txfifo(i2c->dev, (uint8_t *)&d, 1); + moveCnt--; + } else { + i2c_ll_slave_disable_tx_it(i2c->dev); + break; + } } + return pxHigherPriorityTaskWoken; } - return pxHigherPriorityTaskWoken; -} -static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t *i2c, uint32_t len) { + static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len) { #if I2C_SLAVE_USE_RX_QUEUE - uint32_t d = 0; + uint32_t d = 0; #else uint8_t data[SOC_I2C_FIFO_LEN]; #endif - bool pxHigherPriorityTaskWoken = false; + bool pxHigherPriorityTaskWoken = false; #if I2C_SLAVE_USE_RX_QUEUE - while (len > 0) { - i2c_ll_read_rxfifo(i2c->dev, (uint8_t *)&d, 1); - if (xQueueSendFromISR(i2c->rx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) != pdTRUE) { - log_e("rx_queue_full"); - } else { - i2c->rx_data_count++; - } - if (--len == 0) { - len = i2c_ll_get_rxfifo_cnt(i2c->dev); - } + while (len > 0) { + i2c_ll_read_rxfifo(i2c->dev, (uint8_t *)&d, 1); + if (xQueueSendFromISR(i2c->rx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) != pdTRUE) { + log_e("rx_queue_full"); + } else { + i2c->rx_data_count++; + } + if (--len == 0) { + len = i2c_ll_get_rxfifo_cnt(i2c->dev); + } #else if (len) { i2c_ll_read_rxfifo(i2c->dev, data, len); @@ -688,109 +722,109 @@ static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t *i2c, uint32_t len) i2c->rx_data_count += len; } #endif + } + return pxHigherPriorityTaskWoken; } - return pxHigherPriorityTaskWoken; -} - -static void i2c_slave_isr_handler(void *arg) { - bool pxHigherPriorityTaskWoken = false; - i2c_slave_struct_t *i2c = (i2c_slave_struct_t *)arg; // recover data - uint32_t activeInt = 0; - i2c_ll_get_intr_mask(i2c->dev, &activeInt); - i2c_ll_clear_intr_mask(i2c->dev, activeInt); - uint32_t rx_fifo_len = 0; - i2c_ll_get_rxfifo_cnt(i2c->dev, &rx_fifo_len); - bool slave_rw = i2c_ll_slave_rw(i2c->dev); + static void i2c_slave_isr_handler(void *arg) { + bool pxHigherPriorityTaskWoken = false; + i2c_slave_struct_t *i2c = (i2c_slave_struct_t *)arg; // recover data - if (activeInt & I2C_RXFIFO_WM_INT_ENA) { // RX FiFo Full - pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); - i2c_ll_slave_enable_rx_it(i2c->dev); //is this necessary? - } + uint32_t activeInt = 0; + i2c_ll_get_intr_mask(i2c->dev, &activeInt); + i2c_ll_clear_intr_mask(i2c->dev, activeInt); + uint32_t rx_fifo_len = 0; + i2c_ll_get_rxfifo_cnt(i2c->dev, &rx_fifo_len); + bool slave_rw = i2c_ll_slave_rw(i2c->dev); - if (activeInt & I2C_TRANS_COMPLETE_INT_ENA) { // STOP - if (rx_fifo_len) { //READ RX FIFO + if (activeInt & I2C_RXFIFO_WM_INT_ENA) { // RX FiFo Full pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + i2c_ll_slave_enable_rx_it(i2c->dev); //is this necessary? } - if (i2c->rx_data_count) { //WRITE or RepeatedStart - //SEND RX Event - i2c_slave_queue_event_t event; - event.event = I2C_SLAVE_EVT_RX; - event.stop = !slave_rw; - event.param = i2c->rx_data_count; - pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); - //Zero RX count - i2c->rx_data_count = 0; - } - if (slave_rw) { // READ -#if CONFIG_IDF_TARGET_ESP32 - if (i2c->dev->status_reg.scl_main_state_last == 6) { - //SEND TX Event + + if (activeInt & I2C_TRANS_COMPLETE_INT_ENA) { // STOP + if (rx_fifo_len) { //READ RX FIFO + pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + } + if (i2c->rx_data_count) { //WRITE or RepeatedStart + //SEND RX Event i2c_slave_queue_event_t event; - event.event = I2C_SLAVE_EVT_TX; + event.event = I2C_SLAVE_EVT_RX; + event.stop = !slave_rw; + event.param = i2c->rx_data_count; pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); + //Zero RX count + i2c->rx_data_count = 0; } + if (slave_rw) { // READ +#if CONFIG_IDF_TARGET_ESP32 + if (i2c->dev->status_reg.scl_main_state_last == 6) { + //SEND TX Event + i2c_slave_queue_event_t event; + event.event = I2C_SLAVE_EVT_TX; + pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); + } #else //reset TX data i2c_ll_txfifo_rst(i2c->dev); uint8_t d; while (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) == pdTRUE); //flush partial write #endif + } } - } #ifndef CONFIG_IDF_TARGET_ESP32 - if (activeInt & I2C_SLAVE_STRETCH_INT_ENA) { // STRETCH - i2c_stretch_cause_t cause = i2c_ll_stretch_cause(i2c->dev); - if (cause == I2C_STRETCH_CAUSE_MASTER_READ) { - //on C3 RX data disappears with repeated start, so we need to get it here - if (rx_fifo_len) { + if (activeInt & I2C_SLAVE_STRETCH_INT_ENA) { // STRETCH + i2c_stretch_cause_t cause = i2c_ll_stretch_cause(i2c->dev); + if (cause == I2C_STRETCH_CAUSE_MASTER_READ) { + //on C3 RX data disappears with repeated start, so we need to get it here + if (rx_fifo_len) { + pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + } + //SEND TX Event + i2c_slave_queue_event_t event; + event.event = I2C_SLAVE_EVT_TX; + pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); + //will clear after execution + } else if (cause == I2C_STRETCH_CAUSE_TX_FIFO_EMPTY) { + pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); + i2c_ll_stretch_clr(i2c->dev); + } else if (cause == I2C_STRETCH_CAUSE_RX_FIFO_FULL) { pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + i2c_ll_stretch_clr(i2c->dev); } - //SEND TX Event - i2c_slave_queue_event_t event; - event.event = I2C_SLAVE_EVT_TX; - pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); - //will clear after execution - } else if (cause == I2C_STRETCH_CAUSE_TX_FIFO_EMPTY) { - pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); - i2c_ll_stretch_clr(i2c->dev); - } else if (cause == I2C_STRETCH_CAUSE_RX_FIFO_FULL) { - pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); - i2c_ll_stretch_clr(i2c->dev); } - } #endif - if (activeInt & I2C_TXFIFO_WM_INT_ENA) { // TX FiFo Empty - pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); - } + if (activeInt & I2C_TXFIFO_WM_INT_ENA) { // TX FiFo Empty + pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); + } - if (pxHigherPriorityTaskWoken) { - portYIELD_FROM_ISR(); + if (pxHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } } -} -static size_t i2c_slave_read_rx(i2c_slave_struct_t *i2c, uint8_t *data, size_t len) { - if (!len) { - return 0; - } -#if I2C_SLAVE_USE_RX_QUEUE - uint8_t d = 0; - BaseType_t res = pdTRUE; - for (size_t i = 0; i < len; i++) { - if (data) { - res = xQueueReceive(i2c->rx_queue, &data[i], 0); - } else { - res = xQueueReceive(i2c->rx_queue, &d, 0); + static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len) { + if (!len) { + return 0; } - if (res != pdTRUE) { - log_e("Read Queue(%u) Failed", i); - len = i; - break; +#if I2C_SLAVE_USE_RX_QUEUE + uint8_t d = 0; + BaseType_t res = pdTRUE; + for (size_t i = 0; i < len; i++) { + if (data) { + res = xQueueReceive(i2c->rx_queue, &data[i], 0); + } else { + res = xQueueReceive(i2c->rx_queue, &d, 0); + } + if (res != pdTRUE) { + log_e("Read Queue(%u) Failed", i); + len = i; + break; + } } - } - return (data) ? len : 0; + return (data) ? len : 0; #else size_t dlen = 0, to_read = len, so_far = 0, available = 0; uint8_t *rx_data = NULL; @@ -817,55 +851,55 @@ static size_t i2c_slave_read_rx(i2c_slave_struct_t *i2c, uint8_t *data, size_t l } return (data) ? so_far : 0; #endif -} - -static void i2c_slave_task(void *pv_args) { - i2c_slave_struct_t *i2c = (i2c_slave_struct_t *)pv_args; - i2c_slave_queue_event_t event; - size_t len = 0; - bool stop = false; - uint8_t *data = NULL; - for (;;) { - if (xQueueReceive(i2c->event_queue, &event, portMAX_DELAY) == pdTRUE) { - // Write - if (event.event == I2C_SLAVE_EVT_RX) { - len = event.param; - stop = event.stop; - data = (len > 0) ? (uint8_t *)malloc(len) : NULL; - - if (len && data == NULL) { - log_e("Malloc (%u) Failed", len); - } - len = i2c_slave_read_rx(i2c, data, len); - if (i2c->receive_callback) { - i2c->receive_callback(i2c->num, data, len, stop, i2c->arg); - } - free(data); + } - // Read - } else if (event.event == I2C_SLAVE_EVT_TX) { - if (i2c->request_callback) { - i2c->request_callback(i2c->num, i2c->arg); + static void i2c_slave_task(void *pv_args) { + i2c_slave_struct_t *i2c = (i2c_slave_struct_t *)pv_args; + i2c_slave_queue_event_t event; + size_t len = 0; + bool stop = false; + uint8_t *data = NULL; + for (;;) { + if (xQueueReceive(i2c->event_queue, &event, portMAX_DELAY) == pdTRUE) { + // Write + if (event.event == I2C_SLAVE_EVT_RX) { + len = event.param; + stop = event.stop; + data = (len > 0) ? (uint8_t *)malloc(len) : NULL; + + if (len && data == NULL) { + log_e("Malloc (%u) Failed", len); + } + len = i2c_slave_read_rx(i2c, data, len); + if (i2c->receive_callback) { + i2c->receive_callback(i2c->num, data, len, stop, i2c->arg); + } + free(data); + + // Read + } else if (event.event == I2C_SLAVE_EVT_TX) { + if (i2c->request_callback) { + i2c->request_callback(i2c->num, i2c->arg); + } + i2c_ll_stretch_clr(i2c->dev); } - i2c_ll_stretch_clr(i2c->dev); } } + vTaskDelete(NULL); } - vTaskDelete(NULL); -} -static bool i2cSlaveDetachBus(void *bus_i2c_num) { - uint8_t num = (int)bus_i2c_num - 1; - i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; - if (i2c->scl == -1 && i2c->sda == -1) { + static bool i2cSlaveDetachBus(void *bus_i2c_num) { + uint8_t num = (int)bus_i2c_num - 1; + i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; + if (i2c->scl == -1 && i2c->sda == -1) { + return true; + } + esp_err_t err = i2cSlaveDeinit(num); + if (err != ESP_OK) { + log_e("i2cSlaveDeinit failed with error: %d", err); + return false; + } return true; } - esp_err_t err = i2cSlaveDeinit(num); - if (err != ESP_OK) { - log_e("i2cSlaveDeinit failed with error: %d", err); - return false; - } - return true; -} #endif /* SOC_I2C_SUPPORT_SLAVE */ diff --git a/cores/esp32/esp32-hal-i2c.c b/cores/esp32/esp32-hal-i2c.c index 419ce66bb9b..359b2161201 100644 --- a/cores/esp32/esp32-hal-i2c.c +++ b/cores/esp32/esp32-hal-i2c.c @@ -29,6 +29,19 @@ #include "hal/i2c_ll.h" #include "driver/i2c.h" #include "esp32-hal-periman.h" +#include "esp_private/periph_ctrl.h" + +#if SOC_PERIPH_CLK_CTRL_SHARED +#define I2C_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2C_CLOCK_SRC_ATOMIC() +#endif + +#if !SOC_RCC_IS_INDEPENDENT +#define I2C_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2C_RCC_ATOMIC() +#endif #if SOC_I2C_SUPPORT_APB || SOC_I2C_SUPPORT_XTAL #include "esp_private/esp_clk.h" @@ -388,7 +401,9 @@ esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency) { periph_rtc_dig_clk8m_enable(); } #endif - i2c_hal_set_bus_timing(&(hal), frequency, i2c_clk_alloc[src_clk].clk, i2c_clk_alloc[src_clk].clk_freq); + I2C_CLOCK_SRC_ATOMIC() { + i2c_hal_set_bus_timing(&(hal), frequency, i2c_clk_alloc[src_clk].clk, i2c_clk_alloc[src_clk].clk_freq); + } bus[i2c_num].frequency = frequency; //Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2 i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT); diff --git a/cores/esp32/esp32-hal-ledc.c b/cores/esp32/esp32-hal-ledc.c index 7d748f98a56..0a3ec5a60c7 100644 --- a/cores/esp32/esp32-hal-ledc.c +++ b/cores/esp32/esp32-hal-ledc.c @@ -323,11 +323,16 @@ bool ledcOutputInvert(uint8_t pin, bool out_invert) { ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); if (bus != NULL) { gpio_set_level(pin, out_invert); + +#ifdef CONFIG_IDF_TARGET_ESP32P4 + esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT_PAD_OUT0_IDX + ((bus->channel) % 8), out_invert, 0); +#else #ifdef SOC_LEDC_SUPPORT_HS_MODE esp_rom_gpio_connect_out_signal(pin, ((bus->channel / 8 == 0) ? LEDC_HS_SIG_OUT0_IDX : LEDC_LS_SIG_OUT0_IDX) + ((bus->channel) % 8), out_invert, 0); #else esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + ((bus->channel) % 8), out_invert, 0); #endif +#endif // ifdef CONFIG_IDF_TARGET_ESP32P4 return true; } return false; diff --git a/cores/esp32/esp32-hal-matrix.c b/cores/esp32/esp32-hal-matrix.c index fba044d0c85..7cddb4e04db 100644 --- a/cores/esp32/esp32-hal-matrix.c +++ b/cores/esp32/esp32-hal-matrix.c @@ -32,6 +32,8 @@ #include "esp32c6/rom/gpio.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/gpio.h" #else #error Target CONFIG_IDF_TARGET is not supported #endif diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index 7dfca6134b2..ab46eba3d09 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -29,7 +29,7 @@ #endif //CONFIG_BT_ENABLED #include #include "soc/rtc.h" -#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) #include "soc/rtc_cntl_reg.h" #include "soc/syscon_reg.h" #endif @@ -53,6 +53,8 @@ #include "esp32c6/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/rtc.h" #else #error Target CONFIG_IDF_TARGET is not supported diff --git a/cores/esp32/esp32-hal-psram.c b/cores/esp32/esp32-hal-psram.c index 5a741908f07..f28095a6fd8 100644 --- a/cores/esp32/esp32-hal-psram.c +++ b/cores/esp32/esp32-hal-psram.c @@ -27,6 +27,8 @@ #include "esp32s2/rom/cache.h" #elif CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/rom/cache.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/cache.h" #else #error Target CONFIG_IDF_TARGET is not supported #endif diff --git a/cores/esp32/esp32-hal-spi.c b/cores/esp32/esp32-hal-spi.c index 857c3d4bb2e..8c8ce0b7705 100644 --- a/cores/esp32/esp32-hal-spi.c +++ b/cores/esp32/esp32-hal-spi.c @@ -22,11 +22,13 @@ #include "esp_attr.h" #include "soc/spi_reg.h" #include "soc/spi_struct.h" +#include "soc/periph_defs.h" #include "soc/io_mux_reg.h" #include "soc/gpio_sig_map.h" #include "soc/rtc.h" #include "hal/clk_gate_ll.h" #include "esp32-hal-periman.h" +#include "esp_private/periph_ctrl.h" #include "esp_system.h" #include "esp_intr_alloc.h" @@ -55,6 +57,9 @@ #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/ets_sys.h" #include "esp32h2/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/ets_sys.h" +#include "esp32p4/rom/gpio.h" #else #error Target CONFIG_IDF_TARGET is not supported #endif @@ -96,6 +101,24 @@ struct spi_struct_t { #define SPI_FSPI_SS_IDX(n) ((n == 0) ? FSPICS0_OUT_IDX : ((n == 1) ? FSPICS1_OUT_IDX : 0)) #define SPI_SS_IDX(p, n) ((p == 0) ? SPI_FSPI_SS_IDX(n) : ((p == 1) ? SPI_HSPI_SS_IDX(n) : 0)) +#elif CONFIG_IDF_TARGET_ESP32P4 +// ESP32P4 +#define SPI_COUNT (2) // SPI2 and SPI3. SPI0 and SPI1 are reserved for flash and PSRAM + +#define SPI_CLK_IDX(p) ((p == 0) ? SPI2_CK_PAD_OUT_IDX : ((p == 1) ? SPI3_CK_PAD_OUT_IDX : 0)) +#define SPI_MISO_IDX(p) ((p == 0) ? SPI2_Q_PAD_OUT_IDX : ((p == 1) ? SPI3_QO_PAD_OUT_IDX : 0)) +#define SPI_MOSI_IDX(p) ((p == 0) ? SPI2_D_PAD_IN_IDX : ((p == 1) ? SPI3_D_PAD_IN_IDX : 0)) + +#define SPI_HSPI_SS_IDX(n) ((n == 0) ? SPI3_CS_PAD_OUT_IDX : ((n == 1) ? SPI3_CS1_PAD_OUT_IDX : ((n == 2) ? SPI3_CS2_PAD_OUT_IDX : 0))) + +#define SPI_FSPI_SS_IDX(n) \ + ((n == 0) ? SPI2_CS_PAD_OUT_IDX \ + : ((n == 1) ? SPI2_CS1_PAD_OUT_IDX \ + : ((n == 2) ? SPI2_CS2_PAD_OUT_IDX \ + : ((n == 3) ? SPI2_CS3_PAD_OUT_IDX : ((n == 4) ? SPI2_CS4_PAD_OUT_IDX : ((n == 5) ? SPI2_CS5_PAD_OUT_IDX : 0)))))) + +#define SPI_SS_IDX(p, n) ((p == 0) ? SPI_FSPI_SS_IDX(n) : ((p == 1) ? SPI_HSPI_SS_IDX(n) : 0)) + #elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 // ESP32C3 #define SPI_COUNT (1) @@ -125,13 +148,12 @@ struct spi_struct_t { #if CONFIG_DISABLE_HAL_LOCKS #define SPI_MUTEX_LOCK() #define SPI_MUTEX_UNLOCK() - -static spi_t _spi_bus_array[] = { ++ static spi_t _spi_bus_array[] = { #if CONFIG_IDF_TARGET_ESP32S2 {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2, -1, -1, -1, -1} -#elif CONFIG_IDF_TARGET_ESP32S3 +#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1} #elif CONFIG_IDF_TARGET_ESP32C2 {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} @@ -157,7 +179,7 @@ static spi_t _spi_bus_array[] = { {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2, -1, -1, -1, -1} -#elif CONFIG_IDF_TARGET_ESP32S3 +#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 1, -1, -1, -1, -1} #elif CONFIG_IDF_TARGET_ESP32C2 {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} @@ -369,11 +391,10 @@ void spiEnableSSPins(spi_t *spi, uint8_t ss_mask) { return; } SPI_MUTEX_LOCK(); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.val &= ~(ss_mask & SPI_SS_MASK_ALL); -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.val &= ~(ss_mask & SPI_SS_MASK_ALL); +#else + spi->dev->misc.val &= ~(ss_mask & SPI_SS_MASK_ALL); #endif SPI_MUTEX_UNLOCK(); } @@ -383,11 +404,10 @@ void spiDisableSSPins(spi_t *spi, uint8_t ss_mask) { return; } SPI_MUTEX_LOCK(); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.val |= (ss_mask & SPI_SS_MASK_ALL); -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.val |= (ss_mask & SPI_SS_MASK_ALL); +#else + spi->dev->misc.val |= (ss_mask & SPI_SS_MASK_ALL); #endif SPI_MUTEX_UNLOCK(); } @@ -417,11 +437,10 @@ void spiSSSet(spi_t *spi) { return; } SPI_MUTEX_LOCK(); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.cs_keep_active = 1; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.cs_keep_active = 1; +#else + spi->dev->misc.cs_keep_active = 1; #endif SPI_MUTEX_UNLOCK(); } @@ -431,11 +450,10 @@ void spiSSClear(spi_t *spi) { return; } SPI_MUTEX_LOCK(); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.cs_keep_active = 0; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.cs_keep_active = 0; +#else + spi->dev->misc.cs_keep_active = 0; #endif SPI_MUTEX_UNLOCK(); } @@ -460,11 +478,10 @@ uint8_t spiGetDataMode(spi_t *spi) { if (!spi) { return 0; } -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - bool idleEdge = spi->dev->misc.ck_idle_edge; -#else +#if CONFIG_IDF_TARGET_ESP32 bool idleEdge = spi->dev->pin.ck_idle_edge; +#else + bool idleEdge = spi->dev->misc.ck_idle_edge; #endif bool outEdge = spi->dev->user.ck_out_edge; if (idleEdge) { @@ -486,39 +503,35 @@ void spiSetDataMode(spi_t *spi, uint8_t dataMode) { SPI_MUTEX_LOCK(); switch (dataMode) { case SPI_MODE1: -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.ck_idle_edge = 0; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.ck_idle_edge = 0; +#else + spi->dev->misc.ck_idle_edge = 0; #endif spi->dev->user.ck_out_edge = 1; break; case SPI_MODE2: -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.ck_idle_edge = 1; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.ck_idle_edge = 1; +#else + spi->dev->misc.ck_idle_edge = 1; #endif spi->dev->user.ck_out_edge = 1; break; case SPI_MODE3: -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.ck_idle_edge = 1; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.ck_idle_edge = 1; +#else + spi->dev->misc.ck_idle_edge = 1; #endif spi->dev->user.ck_out_edge = 0; break; case SPI_MODE0: default: -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.ck_idle_edge = 0; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.ck_idle_edge = 0; +#else + spi->dev->misc.ck_idle_edge = 0; #endif spi->dev->user.ck_out_edge = 0; break; @@ -564,11 +577,10 @@ static void spiInitBus(spi_t *spi) { spi->dev->slave.trans_done = 0; #endif spi->dev->slave.val = 0; -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.val = 0; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.val = 0; +#else + spi->dev->misc.val = 0; #endif spi->dev->user.val = 0; spi->dev->user1.val = 0; @@ -648,18 +660,18 @@ spi_t *spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST); } -#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#elif defined(__PERIPH_CTRL_ALLOW_LEGACY_API) periph_ll_reset(PERIPH_SPI2_MODULE); periph_ll_enable_clk_clear_rst(PERIPH_SPI2_MODULE); #endif SPI_MUTEX_LOCK(); spiInitBus(spi); -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->clk_gate.clk_en = 1; spi->dev->clk_gate.mst_clk_sel = 1; spi->dev->clk_gate.mst_clk_active = 1; -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 +#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) spi->dev->dma_conf.tx_seg_trans_clr_en = 1; spi->dev->dma_conf.rx_seg_trans_clr_en = 1; spi->dev->dma_conf.dma_seg_trans_en = 0; @@ -670,7 +682,7 @@ spi_t *spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t spi->dev->user.doutdin = 1; int i; for (i = 0; i < 16; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = 0x00000000; #else spi->dev->data_buf[i] = 0x00000000; @@ -697,7 +709,7 @@ void spiWaitReady(spi_t *spi) { #if CONFIG_IDF_TARGET_ESP32S2 #define usr_mosi_dbitlen usr_mosi_bit_len #define usr_miso_dbitlen usr_miso_bit_len -#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#elif !defined(CONFIG_IDF_TARGET_ESP32) #define usr_mosi_dbitlen ms_data_bitlen #define usr_miso_dbitlen ms_data_bitlen #define mosi_dlen ms_dlen @@ -718,13 +730,13 @@ void spiWrite(spi_t *spi, const uint32_t *data, uint8_t len) { spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif for (i = 0; i < len; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = data[i]; #else spi->dev->data_buf[i] = data[i]; #endif } -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -745,20 +757,20 @@ void spiTransfer(spi_t *spi, uint32_t *data, uint8_t len) { spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1; spi->dev->miso_dlen.usr_miso_dbitlen = (len * 32) - 1; for (i = 0; i < len; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = data[i]; #else spi->dev->data_buf[i] = data[i]; #endif } -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while (spi->dev->cmd.usr); for (i = 0; i < len; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 data[i] = spi->dev->data_buf[i].val; #else data[i] = spi->dev->data_buf[i]; @@ -776,13 +788,13 @@ void spiWriteByte(spi_t *spi, uint8_t data) { #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -798,18 +810,18 @@ uint8_t spiTransferByte(spi_t *spi, uint8_t data) { SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; spi->dev->miso_dlen.usr_miso_dbitlen = 7; -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while (spi->dev->cmd.usr); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 data = spi->dev->data_buf[0].val & 0xFF; #else data = spi->dev->data_buf[0] & 0xFF; @@ -839,12 +851,12 @@ void spiWriteWord(spi_t *spi, uint16_t data) { #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -863,18 +875,18 @@ uint16_t spiTransferWord(spi_t *spi, uint16_t data) { SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; spi->dev->miso_dlen.usr_miso_dbitlen = 15; -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while (spi->dev->cmd.usr); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 data = spi->dev->data_buf[0].val; #else data = spi->dev->data_buf[0]; @@ -898,12 +910,12 @@ void spiWriteLong(spi_t *spi, uint32_t data) { #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -922,18 +934,18 @@ uint32_t spiTransferLong(spi_t *spi, uint32_t data) { SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; spi->dev->miso_dlen.usr_miso_dbitlen = 31; -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while (spi->dev->cmd.usr); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 data = spi->dev->data_buf[0].val; #else data = spi->dev->data_buf[0]; @@ -972,14 +984,14 @@ static void __spiTransferBytes(spi_t *spi, const uint8_t *data, uint8_t *out, ui spi->dev->miso_dlen.usr_miso_dbitlen = ((bytes * 8) - 1); for (i = 0; i < words; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = wordsBuf[i]; //copy buffer to spi fifo #else spi->dev->data_buf[i] = wordsBuf[i]; //copy buffer to spi fifo #endif } -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -989,7 +1001,7 @@ static void __spiTransferBytes(spi_t *spi, const uint8_t *data, uint8_t *out, ui if (out) { for (i = 0; i < words; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 wordsBuf[i] = spi->dev->data_buf[i].val; //copy spi fifo to buffer #else wordsBuf[i] = spi->dev->data_buf[i]; //copy spi fifo to buffer @@ -1061,39 +1073,35 @@ void spiTransaction(spi_t *spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bit spi->dev->clock.val = clockDiv; switch (dataMode) { case SPI_MODE1: -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.ck_idle_edge = 0; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.ck_idle_edge = 0; +#else + spi->dev->misc.ck_idle_edge = 0; #endif spi->dev->user.ck_out_edge = 1; break; case SPI_MODE2: -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.ck_idle_edge = 1; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.ck_idle_edge = 1; +#else + spi->dev->misc.ck_idle_edge = 1; #endif spi->dev->user.ck_out_edge = 1; break; case SPI_MODE3: -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.ck_idle_edge = 1; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.ck_idle_edge = 1; +#else + spi->dev->misc.ck_idle_edge = 1; #endif spi->dev->user.ck_out_edge = 0; break; case SPI_MODE0: default: -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \ - || CONFIG_IDF_TARGET_ESP32H2 - spi->dev->misc.ck_idle_edge = 0; -#else +#if CONFIG_IDF_TARGET_ESP32 spi->dev->pin.ck_idle_edge = 0; +#else + spi->dev->misc.ck_idle_edge = 0; #endif spi->dev->user.ck_out_edge = 0; break; @@ -1105,7 +1113,7 @@ void spiTransaction(spi_t *spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bit spi->dev->ctrl.wr_bit_order = 1; spi->dev->ctrl.rd_bit_order = 1; } -#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) // Sync new config with hardware, fixes https://github.com/espressif/arduino-esp32/issues/9221 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); @@ -1134,12 +1142,12 @@ void ARDUINO_ISR_ATTR spiWriteByteNL(spi_t *spi, uint8_t data) { #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -1153,18 +1161,18 @@ uint8_t spiTransferByteNL(spi_t *spi, uint8_t data) { } spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; spi->dev->miso_dlen.usr_miso_dbitlen = 7; -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while (spi->dev->cmd.usr); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 data = spi->dev->data_buf[0].val & 0xFF; #else data = spi->dev->data_buf[0] & 0xFF; @@ -1183,12 +1191,12 @@ void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t *spi, uint16_t data) { #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -1205,18 +1213,18 @@ uint16_t spiTransferShortNL(spi_t *spi, uint16_t data) { } spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; spi->dev->miso_dlen.usr_miso_dbitlen = 15; -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while (spi->dev->cmd.usr); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 data = spi->dev->data_buf[0].val & 0xFFFF; #else data = spi->dev->data_buf[0] & 0xFFFF; @@ -1238,12 +1246,12 @@ void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t *spi, uint32_t data) { #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -1260,18 +1268,18 @@ uint32_t spiTransferLongNL(spi_t *spi, uint32_t data) { } spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; spi->dev->miso_dlen.usr_miso_dbitlen = 31; -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while (spi->dev->cmd.usr); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 data = spi->dev->data_buf[0].val; #else data = spi->dev->data_buf[0]; @@ -1302,13 +1310,13 @@ void spiWriteNL(spi_t *spi, const void *data_in, uint32_t len) { spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif for (size_t i = 0; i < c_longs; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = data[i]; #else spi->dev->data_buf[i] = data[i]; #endif } -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -1341,7 +1349,7 @@ void spiTransferBytesNL(spi_t *spi, const void *data_in, uint8_t *data_out, uint spi->dev->miso_dlen.usr_miso_dbitlen = (c_len * 8) - 1; if (data) { for (size_t i = 0; i < c_longs; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = data[i]; #else spi->dev->data_buf[i] = data[i]; @@ -1349,14 +1357,14 @@ void spiTransferBytesNL(spi_t *spi, const void *data_in, uint8_t *data_out, uint } } else { for (size_t i = 0; i < c_longs; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = 0xFFFFFFFF; #else spi->dev->data_buf[i] = 0xFFFFFFFF; #endif } } -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -1365,13 +1373,13 @@ void spiTransferBytesNL(spi_t *spi, const void *data_in, uint8_t *data_out, uint if (result) { if (c_len & 3) { for (size_t i = 0; i < (c_longs - 1); i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 result[i] = spi->dev->data_buf[i].val; #else result[i] = spi->dev->data_buf[i]; #endif } -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 uint32_t last_data = spi->dev->data_buf[c_longs - 1].val; #else uint32_t last_data = spi->dev->data_buf[c_longs - 1]; @@ -1383,7 +1391,7 @@ void spiTransferBytesNL(spi_t *spi, const void *data_in, uint8_t *data_out, uint } } else { for (size_t i = 0; i < c_longs; i++) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 result[i] = spi->dev->data_buf[i].val; #else result[i] = spi->dev->data_buf[i]; @@ -1425,18 +1433,18 @@ void spiTransferBitsNL(spi_t *spi, uint32_t data, uint32_t *out, uint8_t bits) { spi->dev->mosi_dlen.usr_mosi_dbitlen = (bits - 1); spi->dev->miso_dlen.usr_miso_dbitlen = (bits - 1); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[0].val = data; #else spi->dev->data_buf[0] = data; #endif -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while (spi->dev->cmd.usr); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 data = spi->dev->data_buf[0].val; #else data = spi->dev->data_buf[0]; @@ -1477,34 +1485,34 @@ void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t *spi, const void *data_in, uint32_t if (msb) { if (l_bytes && i == (c_longs - 1)) { if (l_bytes == 2) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 MSB_16_SET(spi->dev->data_buf[i].val, data[i]); #else MSB_16_SET(spi->dev->data_buf[i], data[i]); #endif } else { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = data[i] & 0xFF; #else spi->dev->data_buf[i] = data[i] & 0xFF; #endif } } else { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 MSB_PIX_SET(spi->dev->data_buf[i].val, data[i]); #else MSB_PIX_SET(spi->dev->data_buf[i], data[i]); #endif } } else { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 spi->dev->data_buf[i].val = data[i]; #else spi->dev->data_buf[i] = data[i]; #endif } } -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif @@ -1528,7 +1536,7 @@ typedef union { uint32_t clkcnt_l : 6; /*it must be equal to spi_clkcnt_N.*/ uint32_t clkcnt_h : 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/ uint32_t clkcnt_n : 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/ -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) uint32_t clkdiv_pre : 4; /*it is pre-divider of spi_clk.*/ uint32_t reserved : 9; /*reserved*/ #else @@ -1573,7 +1581,7 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq) { while (calPreVari++ <= 1) { calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari; -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) if (calPre > 0xF) { reg.clkdiv_pre = 0xF; #else diff --git a/cores/esp32/esp32-hal-spi.h b/cores/esp32/esp32-hal-spi.h index a238cada87d..b77abff7854 100644 --- a/cores/esp32/esp32-hal-spi.h +++ b/cores/esp32/esp32-hal-spi.h @@ -28,10 +28,7 @@ extern "C" { #define SPI_HAS_TRANSACTION -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32S3 -#define FSPI 0 -#define HSPI 1 -#elif CONFIG_IDF_TARGET_ESP32S2 +#ifdef CONFIG_IDF_TARGET_ESP32S2 #define FSPI 1 //SPI 1 bus. ESP32S2: for external memory only (can use the same data lines but different SS) #define HSPI 2 //SPI 2 bus. ESP32S2: external memory or device - it can be matrixed to any pins #define SPI2 2 // Another name for ESP32S2 SPI 2 @@ -40,6 +37,9 @@ extern "C" { #define FSPI 1 //SPI 1 bus attached to the flash (can use the same data lines but different SS) #define HSPI 2 //SPI 2 bus normally mapped to pins 12 - 15, but can be matrixed to any pins #define VSPI 3 //SPI 3 bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins +#else +#define FSPI 0 +#define HSPI 1 #endif // This defines are not representing the real Divider of the ESP32 diff --git a/cores/esp32/esp32-hal-touch.c b/cores/esp32/esp32-hal-touch.c index 764b7dbb73f..4c0ed92656c 100644 --- a/cores/esp32/esp32-hal-touch.c +++ b/cores/esp32/esp32-hal-touch.c @@ -14,6 +14,10 @@ #include "soc/soc_caps.h" #if SOC_TOUCH_SENSOR_SUPPORTED +#if SOC_TOUCH_SENSOR_VERSION == 3 // ESP32P4 +// ToDo: Implement touch sensor for ESP32P4 +#warning "Touch sensor not implemented for ESP32P4 yet" +#else #include "driver/touch_sensor.h" #include "esp32-hal-touch.h" #include "esp32-hal-periman.h" @@ -22,7 +26,7 @@ Internal Private Touch Data Structure and Functions */ -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 static uint16_t __touchSleepCycles = 0x1000; static uint16_t __touchMeasureCycles = 0x1000; #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 @@ -51,7 +55,7 @@ static bool initialized = false; static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = {false}; static void ARDUINO_ISR_ATTR __touchISR(void *arg) { -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 uint32_t pad_intr = touch_pad_get_status(); //clear interrupt touch_pad_clear_status(); @@ -93,7 +97,7 @@ static void ARDUINO_ISR_ATTR __touchISR(void *arg) { static void __touchSetCycles(uint16_t measure, uint16_t sleep) { __touchSleepCycles = sleep; __touchMeasureCycles = measure; -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 touch_pad_set_measurement_clock_cycles(measure); #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 touch_pad_set_charge_discharge_times(measure); @@ -123,7 +127,7 @@ static void __touchInit() { esp_err_t err = ESP_OK; -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 err = touch_pad_init(); if (err != ESP_OK) { goto err; @@ -143,7 +147,7 @@ static void __touchInit() { if (err != ESP_OK) { goto err; } - touch_pad_intr_enable(); // returns ESP_OK + touch_pad_intr_enable(); // returns ESP_OK #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 err = touch_pad_init(); if (err != ESP_OK) { @@ -179,11 +183,11 @@ static void __touchChannelInit(int pad) { return; } -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 // Initial no Threshold and setup __touchInterruptHandlers[pad].fn = NULL; touch_pad_config(pad, TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK -#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 // Initial no Threshold and setup __touchInterruptHandlers[pad].fn = NULL; touch_pad_config(pad); // returns ESP_OK @@ -270,7 +274,7 @@ static void __touchDettachInterrupt(uint8_t pin) { External Public Touch API Functions */ -#if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC +#if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC void touchInterruptSetThresholdDirection(bool mustbeLower) { if (mustbeLower) { touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW); @@ -324,4 +328,5 @@ extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value extern void touchDetachInterrupt(uint8_t) __attribute__((weak, alias("__touchDettachInterrupt"))); extern void touchSetCycles(uint16_t, uint16_t) __attribute__((weak, alias("__touchSetCycles"))); +#endif /* SOC_TOUCH_SENSOR_VERSION == 3 */ #endif /* SOC_TOUCH_SENSOR_SUPPORTED */ diff --git a/cores/esp32/esp32-hal-touch.h b/cores/esp32/esp32-hal-touch.h index 115d6cdc9cf..cc140d81bb0 100644 --- a/cores/esp32/esp32-hal-touch.h +++ b/cores/esp32/esp32-hal-touch.h @@ -37,6 +37,8 @@ extern "C" { typedef uint16_t touch_value_t; #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2 ESP32S3 typedef uint32_t touch_value_t; +#elif SOC_TOUCH_SENSOR_VERSION == 3 // ESP32P4 +typedef uint32_t touch_value_t; #endif /* diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 2af23e075cc..82c9d8808d0 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -625,7 +625,7 @@ void uartSetRxInvert(uart_t *uart, bool invert) { if (uart == NULL) { return; } -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 // POTENTIAL ISSUE :: original code only set/reset rxd_inv bit // IDF or LL set/reset the whole inv_mask! // if (invert) @@ -898,7 +898,7 @@ int log_printfv(const char *format, va_list arg) { #endif */ #if (ARDUINO_USB_CDC_ON_BOOT == 1 && ARDUINO_USB_MODE == 0) || CONFIG_IDF_TARGET_ESP32C3 \ - || ((CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6) && ARDUINO_USB_CDC_ON_BOOT == 1) + || ((CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4) && ARDUINO_USB_CDC_ON_BOOT == 1) vsnprintf(temp, len + 1, format, arg); ets_printf("%s", temp); #else @@ -1105,6 +1105,20 @@ unsigned long uartDetectBaudrate(uart_t *uart) { */ // gets the right TX or RX SIGNAL, based on the UART number from gpio_sig_map.h +#ifdef CONFIG_IDF_TARGET_ESP32P4 +#define UART_TX_SIGNAL(uartNumber) \ + (uartNumber == UART_NUM_0 \ + ? UART0_TXD_PAD_OUT_IDX \ + : (uartNumber == UART_NUM_1 \ + ? UART1_TXD_PAD_OUT_IDX \ + : (uartNumber == UART_NUM_2 ? UART2_TXD_PAD_OUT_IDX : (uartNumber == UART_NUM_3 ? UART3_TXD_PAD_OUT_IDX : UART4_TXD_PAD_OUT_IDX)))) +#define UART_RX_SIGNAL(uartNumber) \ + (uartNumber == UART_NUM_0 \ + ? UART0_RXD_PAD_IN_IDX \ + : (uartNumber == UART_NUM_1 \ + ? UART1_RXD_PAD_IN_IDX \ + : (uartNumber == UART_NUM_2 ? UART2_RXD_PAD_IN_IDX : (uartNumber == UART_NUM_3 ? UART3_RXD_PAD_IN_IDX : UART4_RXD_PAD_IN_IDX)))) +#else #if SOC_UART_HP_NUM > 2 #define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : (uartNumber == UART_NUM_1 ? U1TXD_OUT_IDX : U2TXD_OUT_IDX)) #define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : (uartNumber == UART_NUM_1 ? U1RXD_IN_IDX : U2RXD_IN_IDX)) @@ -1112,6 +1126,8 @@ unsigned long uartDetectBaudrate(uart_t *uart) { #define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : U1TXD_OUT_IDX) #define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : U1RXD_IN_IDX) #endif +#endif // ifdef CONFIG_IDF_TARGET_ESP32P4 + /* This function internally binds defined UARTs TX signal with defined RX pin of any UART (same or different). This creates a loop that lets us receive anything we send on the UART without external wires. diff --git a/docs/en/lib_builder.rst b/docs/en/lib_builder.rst index 3d28761ab2d..fc488566878 100644 --- a/docs/en/lib_builder.rst +++ b/docs/en/lib_builder.rst @@ -157,6 +157,7 @@ This build command will build for the ESP32-S3 target. You can specify other tar * esp32c3 * esp32c6 * esp32h2 +* esp32p4 Set Build Type ^^^^^^^^^^^^^^ diff --git a/idf_component.yml b/idf_component.yml index 4b3e582d256..3b83650bf5b 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -21,6 +21,7 @@ files: - "variants/esp32c3/**/*" - "variants/esp32c6/**/*" - "variants/esp32h2/**/*" + - "variants/esp32p4/**/*" exclude: - "docs/" - "docs/**/*" diff --git a/libraries/ArduinoOTA/examples/BasicOTA/ci.json b/libraries/ArduinoOTA/examples/BasicOTA/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/ArduinoOTA/examples/BasicOTA/ci.json +++ b/libraries/ArduinoOTA/examples/BasicOTA/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/AsyncUDP/examples/AsyncUDPClient/ci.json b/libraries/AsyncUDP/examples/AsyncUDPClient/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/AsyncUDP/examples/AsyncUDPClient/ci.json +++ b/libraries/AsyncUDP/examples/AsyncUDPClient/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/ci.json b/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/ci.json +++ b/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/AsyncUDP/examples/AsyncUDPServer/ci.json b/libraries/AsyncUDP/examples/AsyncUDPServer/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/AsyncUDP/examples/AsyncUDPServer/ci.json +++ b/libraries/AsyncUDP/examples/AsyncUDPServer/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/BLE/examples/BLE5_extended_scan/ci.json b/libraries/BLE/examples/BLE5_extended_scan/ci.json index edef5051e09..e97e4cf7fea 100644 --- a/libraries/BLE/examples/BLE5_extended_scan/ci.json +++ b/libraries/BLE/examples/BLE5_extended_scan/ci.json @@ -1,6 +1,7 @@ { "targets": { "esp32": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/BLE5_multi_advertising/ci.json b/libraries/BLE/examples/BLE5_multi_advertising/ci.json index edef5051e09..fc9f75986fe 100644 --- a/libraries/BLE/examples/BLE5_multi_advertising/ci.json +++ b/libraries/BLE/examples/BLE5_multi_advertising/ci.json @@ -1,6 +1,6 @@ { "targets": { - "esp32": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json index edef5051e09..a034e239a3f 100644 --- a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json +++ b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json @@ -1,6 +1,10 @@ { "targets": { "esp32": false, - "esp32s2": false + "esp32c2": false, + "esp32c3": false, + "esp32p4": false, + "esp32s2": false, + "esp32s3": false } } diff --git a/libraries/BLE/examples/BLE5_periodic_sync/ci.json b/libraries/BLE/examples/BLE5_periodic_sync/ci.json index edef5051e09..715becda6cb 100644 --- a/libraries/BLE/examples/BLE5_periodic_sync/ci.json +++ b/libraries/BLE/examples/BLE5_periodic_sync/ci.json @@ -1,6 +1,10 @@ { "targets": { "esp32": false, + "esp32c3": false, + "esp32c6": false, + "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/Beacon_Scanner/ci.json b/libraries/BLE/examples/Beacon_Scanner/ci.json index 1443137ab0d..ee810400be6 100644 --- a/libraries/BLE/examples/Beacon_Scanner/ci.json +++ b/libraries/BLE/examples/Beacon_Scanner/ci.json @@ -1,5 +1,9 @@ { "targets": { + "esp32c3": false, + "esp32c6": false, + "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/Client/ci.json b/libraries/BLE/examples/Client/ci.json index 1443137ab0d..eb6596c4a37 100644 --- a/libraries/BLE/examples/Client/ci.json +++ b/libraries/BLE/examples/Client/ci.json @@ -1,5 +1,7 @@ { "targets": { + "esp32c3": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json b/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json index 521ae8f5ff1..156dda6560c 100644 --- a/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json +++ b/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json @@ -1,6 +1,7 @@ { "targets": { "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/EddystoneURL_Beacon/ci.json b/libraries/BLE/examples/EddystoneURL_Beacon/ci.json index 521ae8f5ff1..156dda6560c 100644 --- a/libraries/BLE/examples/EddystoneURL_Beacon/ci.json +++ b/libraries/BLE/examples/EddystoneURL_Beacon/ci.json @@ -1,6 +1,7 @@ { "targets": { "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/Notify/ci.json b/libraries/BLE/examples/Notify/ci.json index 1443137ab0d..156dda6560c 100644 --- a/libraries/BLE/examples/Notify/ci.json +++ b/libraries/BLE/examples/Notify/ci.json @@ -1,5 +1,7 @@ { "targets": { + "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/Scan/ci.json b/libraries/BLE/examples/Scan/ci.json index 1443137ab0d..fc9f75986fe 100644 --- a/libraries/BLE/examples/Scan/ci.json +++ b/libraries/BLE/examples/Scan/ci.json @@ -1,5 +1,6 @@ { "targets": { + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/Server/ci.json b/libraries/BLE/examples/Server/ci.json index 1443137ab0d..a034e239a3f 100644 --- a/libraries/BLE/examples/Server/ci.json +++ b/libraries/BLE/examples/Server/ci.json @@ -1,5 +1,10 @@ { "targets": { - "esp32s2": false + "esp32": false, + "esp32c2": false, + "esp32c3": false, + "esp32p4": false, + "esp32s2": false, + "esp32s3": false } } diff --git a/libraries/BLE/examples/Server_multiconnect/ci.json b/libraries/BLE/examples/Server_multiconnect/ci.json index 1443137ab0d..715becda6cb 100644 --- a/libraries/BLE/examples/Server_multiconnect/ci.json +++ b/libraries/BLE/examples/Server_multiconnect/ci.json @@ -1,5 +1,10 @@ { "targets": { + "esp32": false, + "esp32c3": false, + "esp32c6": false, + "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/UART/ci.json b/libraries/BLE/examples/UART/ci.json index 1443137ab0d..ee810400be6 100644 --- a/libraries/BLE/examples/UART/ci.json +++ b/libraries/BLE/examples/UART/ci.json @@ -1,5 +1,9 @@ { "targets": { + "esp32c3": false, + "esp32c6": false, + "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/Write/ci.json b/libraries/BLE/examples/Write/ci.json index 1443137ab0d..eb6596c4a37 100644 --- a/libraries/BLE/examples/Write/ci.json +++ b/libraries/BLE/examples/Write/ci.json @@ -1,5 +1,7 @@ { "targets": { + "esp32c3": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BLE/examples/iBeacon/ci.json b/libraries/BLE/examples/iBeacon/ci.json index 1443137ab0d..156dda6560c 100644 --- a/libraries/BLE/examples/iBeacon/ci.json +++ b/libraries/BLE/examples/iBeacon/ci.json @@ -1,5 +1,7 @@ { "targets": { + "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json b/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json +++ b/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json b/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json +++ b/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json +++ b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json +++ b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/DNSServer/examples/CaptivePortal/ci.json b/libraries/DNSServer/examples/CaptivePortal/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/DNSServer/examples/CaptivePortal/ci.json +++ b/libraries/DNSServer/examples/CaptivePortal/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/ci.json b/libraries/ESP32/examples/Camera/CameraWebServer/ci.json index 25c42144223..cd679adefad 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/ci.json +++ b/libraries/ESP32/examples/Camera/CameraWebServer/ci.json @@ -2,6 +2,7 @@ "targets": { "esp32c3": false, "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ci.json b/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ci.json index 25c42144223..cd679adefad 100644 --- a/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ci.json +++ b/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ci.json @@ -2,6 +2,7 @@ "targets": { "esp32c3": false, "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/ci.json b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/ci.json +++ b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino index eada1c7ea6b..17e7af290bf 100644 --- a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino +++ b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino @@ -21,7 +21,7 @@ * */ -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 // ESP32 C3 has only 2 channels for RX and 2 for TX, thus MAX RMT_MEM is 128 #define RMT_TX_PIN 4 #define RMT_RX_PIN 5 diff --git a/libraries/ESP32/examples/ResetReason/ResetReason/ResetReason.ino b/libraries/ESP32/examples/ResetReason/ResetReason/ResetReason.ino index 3c9dbb9b12f..0104c6422f2 100644 --- a/libraries/ESP32/examples/ResetReason/ResetReason/ResetReason.ino +++ b/libraries/ESP32/examples/ResetReason/ResetReason/ResetReason.ino @@ -26,6 +26,8 @@ #include "esp32c6/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/rtc.h" #else #error Target CONFIG_IDF_TARGET is not supported #endif diff --git a/libraries/ESP32/examples/Time/SimpleTime/ci.json b/libraries/ESP32/examples/Time/SimpleTime/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/ESP32/examples/Time/SimpleTime/ci.json +++ b/libraries/ESP32/examples/Time/SimpleTime/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/ci.json b/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/ci.json index 7cfaa76784d..7b73237d754 100644 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/ci.json +++ b/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/ci.json @@ -4,6 +4,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/ci.json b/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/ci.json index 7cfaa76784d..7b73237d754 100644 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/ci.json +++ b/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/ci.json @@ -4,6 +4,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/ci.json b/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/ci.json index 7cfaa76784d..7b73237d754 100644 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/ci.json +++ b/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/ci.json @@ -4,6 +4,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/ci.json b/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/ci.json index 7cfaa76784d..7b73237d754 100644 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/ci.json +++ b/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/ci.json @@ -4,6 +4,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP_SR/examples/Basic/ci.json b/libraries/ESP_SR/examples/Basic/ci.json index dca52699ab3..98703e79183 100644 --- a/libraries/ESP_SR/examples/Basic/ci.json +++ b/libraries/ESP_SR/examples/Basic/ci.json @@ -9,6 +9,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/ESPmDNS/examples/mDNS-SD_Extended/ci.json b/libraries/ESPmDNS/examples/mDNS-SD_Extended/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/ESPmDNS/examples/mDNS-SD_Extended/ci.json +++ b/libraries/ESPmDNS/examples/mDNS-SD_Extended/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESPmDNS/examples/mDNS_Web_Server/ci.json b/libraries/ESPmDNS/examples/mDNS_Web_Server/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/ESPmDNS/examples/mDNS_Web_Server/ci.json +++ b/libraries/ESPmDNS/examples/mDNS_Web_Server/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Ethernet/examples/ETH_WIFI_BRIDGE/ci.json b/libraries/Ethernet/examples/ETH_WIFI_BRIDGE/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/Ethernet/examples/ETH_WIFI_BRIDGE/ci.json +++ b/libraries/Ethernet/examples/ETH_WIFI_BRIDGE/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index bc5a94484da..13f9c11f7fe 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -30,7 +30,9 @@ #include "driver/gpio.h" #include "driver/spi_master.h" #if CONFIG_ETH_USE_ESP32_EMAC +#if defined __has_include && __has_include("soc/emac_ext_struct.h") #include "soc/emac_ext_struct.h" +#endif /* __has_include("soc/emac_ext_struct.h" */ #include "soc/rtc.h" #endif /* CONFIG_ETH_USE_ESP32_EMAC */ #include "esp32-hal-periman.h" @@ -146,7 +148,7 @@ void ETHClass::setTaskStackSize(size_t size) { _task_stack_size = size; } -#if CONFIG_ETH_USE_ESP32_EMAC +#if (CONFIG_ETH_USE_ESP32_EMAC && !defined(CONFIG_IDF_TARGET_ESP32P4)) bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clock_mode) { esp_err_t ret = ESP_OK; if (_eth_index > 2) { @@ -898,7 +900,7 @@ void ETHClass::end(void) { #if ETH_SPI_SUPPORTS_CUSTOM _spi = NULL; #endif -#if CONFIG_ETH_USE_ESP32_EMAC +#if (CONFIG_ETH_USE_ESP32_EMAC && !defined(CONFIG_IDF_TARGET_ESP32P4)) perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_RMII, empty_ethDetachBus); perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_CLK, empty_ethDetachBus); perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_MCD, empty_ethDetachBus); diff --git a/libraries/FFat/examples/FFat_time/ci.json b/libraries/FFat/examples/FFat_time/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/FFat/examples/FFat_time/ci.json +++ b/libraries/FFat/examples/FFat_time/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPClient/examples/Authorization/ci.json b/libraries/HTTPClient/examples/Authorization/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPClient/examples/Authorization/ci.json +++ b/libraries/HTTPClient/examples/Authorization/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPClient/examples/BasicHttpClient/ci.json b/libraries/HTTPClient/examples/BasicHttpClient/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPClient/examples/BasicHttpClient/ci.json +++ b/libraries/HTTPClient/examples/BasicHttpClient/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPClient/examples/BasicHttpsClient/ci.json b/libraries/HTTPClient/examples/BasicHttpsClient/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPClient/examples/BasicHttpsClient/ci.json +++ b/libraries/HTTPClient/examples/BasicHttpsClient/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json +++ b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPClient/examples/ReuseConnection/ci.json b/libraries/HTTPClient/examples/ReuseConnection/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPClient/examples/ReuseConnection/ci.json +++ b/libraries/HTTPClient/examples/ReuseConnection/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPClient/examples/StreamHttpClient/ci.json b/libraries/HTTPClient/examples/StreamHttpClient/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPClient/examples/StreamHttpClient/ci.json +++ b/libraries/HTTPClient/examples/StreamHttpClient/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPUpdate/examples/httpUpdate/ci.json b/libraries/HTTPUpdate/examples/httpUpdate/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPUpdate/examples/httpUpdate/ci.json +++ b/libraries/HTTPUpdate/examples/httpUpdate/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/ci.json b/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/ci.json +++ b/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json +++ b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/HTTPUpdateServer/examples/WebUpdater/ci.json b/libraries/HTTPUpdateServer/examples/WebUpdater/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/HTTPUpdateServer/examples/WebUpdater/ci.json +++ b/libraries/HTTPUpdateServer/examples/WebUpdater/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Insights/examples/DiagnosticsSmokeTest/ci.json b/libraries/Insights/examples/DiagnosticsSmokeTest/ci.json index 90f5ecfe4d2..0d8130e329a 100644 --- a/libraries/Insights/examples/DiagnosticsSmokeTest/ci.json +++ b/libraries/Insights/examples/DiagnosticsSmokeTest/ci.json @@ -1,6 +1,7 @@ { "targets": { "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Insights/examples/MinimalDiagnostics/ci.json b/libraries/Insights/examples/MinimalDiagnostics/ci.json index 90f5ecfe4d2..0d8130e329a 100644 --- a/libraries/Insights/examples/MinimalDiagnostics/ci.json +++ b/libraries/Insights/examples/MinimalDiagnostics/ci.json @@ -1,6 +1,7 @@ { "targets": { "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/LittleFS/examples/LITTLEFS_time/ci.json b/libraries/LittleFS/examples/LITTLEFS_time/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/LittleFS/examples/LITTLEFS_time/ci.json +++ b/libraries/LittleFS/examples/LITTLEFS_time/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/NetBIOS/examples/ESP_NBNST/ci.json b/libraries/NetBIOS/examples/ESP_NBNST/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/NetBIOS/examples/ESP_NBNST/ci.json +++ b/libraries/NetBIOS/examples/ESP_NBNST/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientInsecure/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientInsecure/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientInsecure/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientInsecure/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientPSK/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientPSK/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientPSK/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientPSK/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureProtocolUpgrade/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecureProtocolUpgrade/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecureProtocolUpgrade/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureProtocolUpgrade/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientShowPeerCredentials/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientShowPeerCredentials/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientShowPeerCredentials/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientShowPeerCredentials/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientTrustOnFirstUse/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientTrustOnFirstUse/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientTrustOnFirstUse/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientTrustOnFirstUse/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/OpenThread/examples/COAP/coap_lamp/ci.json b/libraries/OpenThread/examples/COAP/coap_lamp/ci.json index c60d9179992..a034e239a3f 100644 --- a/libraries/OpenThread/examples/COAP/coap_lamp/ci.json +++ b/libraries/OpenThread/examples/COAP/coap_lamp/ci.json @@ -3,6 +3,7 @@ "esp32": false, "esp32c2": false, "esp32c3": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/OpenThread/examples/COAP/coap_switch/ci.json b/libraries/OpenThread/examples/COAP/coap_switch/ci.json index c60d9179992..715becda6cb 100644 --- a/libraries/OpenThread/examples/COAP/coap_switch/ci.json +++ b/libraries/OpenThread/examples/COAP/coap_switch/ci.json @@ -1,9 +1,10 @@ { "targets": { "esp32": false, - "esp32c2": false, "esp32c3": false, - "esp32s2": false, - "esp32s3": false + "esp32c6": false, + "esp32h2": false, + "esp32p4": false, + "esp32s2": false } } diff --git a/libraries/OpenThread/examples/SimpleCLI/ci.json b/libraries/OpenThread/examples/SimpleCLI/ci.json index c60d9179992..ee810400be6 100644 --- a/libraries/OpenThread/examples/SimpleCLI/ci.json +++ b/libraries/OpenThread/examples/SimpleCLI/ci.json @@ -1,9 +1,9 @@ { "targets": { - "esp32": false, - "esp32c2": false, "esp32c3": false, - "esp32s2": false, - "esp32s3": false + "esp32c6": false, + "esp32h2": false, + "esp32p4": false, + "esp32s2": false } } diff --git a/libraries/OpenThread/examples/SimpleNode/ci.json b/libraries/OpenThread/examples/SimpleNode/ci.json index c60d9179992..eb6596c4a37 100644 --- a/libraries/OpenThread/examples/SimpleNode/ci.json +++ b/libraries/OpenThread/examples/SimpleNode/ci.json @@ -1,9 +1,7 @@ { "targets": { - "esp32": false, - "esp32c2": false, "esp32c3": false, - "esp32s2": false, - "esp32s3": false + "esp32p4": false, + "esp32s2": false } } diff --git a/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json b/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json index c60d9179992..156dda6560c 100644 --- a/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json +++ b/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json @@ -1,9 +1,7 @@ { "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false + "esp32h2": false, + "esp32p4": false, + "esp32s2": false } } diff --git a/libraries/OpenThread/examples/SimpleThreadNetwork/LeaderNode/ci.json b/libraries/OpenThread/examples/SimpleThreadNetwork/LeaderNode/ci.json index c60d9179992..a034e239a3f 100644 --- a/libraries/OpenThread/examples/SimpleThreadNetwork/LeaderNode/ci.json +++ b/libraries/OpenThread/examples/SimpleThreadNetwork/LeaderNode/ci.json @@ -3,6 +3,7 @@ "esp32": false, "esp32c2": false, "esp32c3": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/OpenThread/examples/SimpleThreadNetwork/RouterNode/ci.json b/libraries/OpenThread/examples/SimpleThreadNetwork/RouterNode/ci.json index c60d9179992..a034e239a3f 100644 --- a/libraries/OpenThread/examples/SimpleThreadNetwork/RouterNode/ci.json +++ b/libraries/OpenThread/examples/SimpleThreadNetwork/RouterNode/ci.json @@ -3,6 +3,7 @@ "esp32": false, "esp32c2": false, "esp32c3": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/OpenThread/examples/ThreadScan/ci.json b/libraries/OpenThread/examples/ThreadScan/ci.json index c60d9179992..a034e239a3f 100644 --- a/libraries/OpenThread/examples/ThreadScan/ci.json +++ b/libraries/OpenThread/examples/ThreadScan/ci.json @@ -3,6 +3,7 @@ "esp32": false, "esp32c2": false, "esp32c3": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/OpenThread/examples/onReceive/ci.json b/libraries/OpenThread/examples/onReceive/ci.json index c60d9179992..a034e239a3f 100644 --- a/libraries/OpenThread/examples/onReceive/ci.json +++ b/libraries/OpenThread/examples/onReceive/ci.json @@ -3,6 +3,7 @@ "esp32": false, "esp32c2": false, "esp32c3": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/PPP/examples/PPP_WIFI_BRIDGE/ci.json b/libraries/PPP/examples/PPP_WIFI_BRIDGE/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/PPP/examples/PPP_WIFI_BRIDGE/ci.json +++ b/libraries/PPP/examples/PPP_WIFI_BRIDGE/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/PPP/src/PPP.cpp b/libraries/PPP/src/PPP.cpp index 28d6ddd8396..e77a78b77b7 100644 --- a/libraries/PPP/src/PPP.cpp +++ b/libraries/PPP/src/PPP.cpp @@ -7,6 +7,7 @@ #include #include "driver/uart.h" #include "hal/uart_ll.h" +#include "esp_private/uart_share_hw_ctrl.h" #define PPP_CMD_MODE_CHECK(x) \ if (_dce == NULL) { \ @@ -653,7 +654,10 @@ bool PPPClass::setBaudrate(int baudrate) { log_e("uart_get_sclk_freq failed with %d %s", err, esp_err_to_name(err)); return false; } - uart_ll_set_baudrate(UART_LL_GET_HW(_uart_num), (uint32_t)baudrate, sclk_freq); + + HP_UART_SRC_CLK_ATOMIC() { + uart_ll_set_baudrate(UART_LL_GET_HW(_uart_num), (uint32_t)baudrate, sclk_freq); + } return true; } diff --git a/libraries/RainMaker/examples/RMakerCustom/ci.json b/libraries/RainMaker/examples/RMakerCustom/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/RainMaker/examples/RMakerCustom/ci.json +++ b/libraries/RainMaker/examples/RMakerCustom/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json b/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json +++ b/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json b/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json +++ b/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/RainMaker/examples/RMakerSwitch/ci.json b/libraries/RainMaker/examples/RMakerSwitch/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/RainMaker/examples/RMakerSwitch/ci.json +++ b/libraries/RainMaker/examples/RMakerSwitch/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/SD/examples/SD_time/ci.json b/libraries/SD/examples/SD_time/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/SD/examples/SD_time/ci.json +++ b/libraries/SD/examples/SD_time/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/SD_MMC/examples/SD2USBMSC/ci.json b/libraries/SD_MMC/examples/SD2USBMSC/ci.json index 97ae5ee5616..715becda6cb 100644 --- a/libraries/SD_MMC/examples/SD2USBMSC/ci.json +++ b/libraries/SD_MMC/examples/SD2USBMSC/ci.json @@ -4,6 +4,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/SD_MMC/examples/SDMMC_Test/ci.json b/libraries/SD_MMC/examples/SDMMC_Test/ci.json index 35b6e255471..ee810400be6 100644 --- a/libraries/SD_MMC/examples/SDMMC_Test/ci.json +++ b/libraries/SD_MMC/examples/SDMMC_Test/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/SD_MMC/examples/SDMMC_time/ci.json b/libraries/SD_MMC/examples/SDMMC_time/ci.json index 35b6e255471..ee810400be6 100644 --- a/libraries/SD_MMC/examples/SDMMC_time/ci.json +++ b/libraries/SD_MMC/examples/SDMMC_time/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/SD_MMC/src/SD_MMC.cpp b/libraries/SD_MMC/src/SD_MMC.cpp index 6bbcf44d010..80cb150baa2 100644 --- a/libraries/SD_MMC/src/SD_MMC.cpp +++ b/libraries/SD_MMC/src/SD_MMC.cpp @@ -35,6 +35,7 @@ using namespace fs; SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) { +#if !defined(CONFIG_IDF_TARGET_ESP32P4) #if defined(SOC_SDMMC_USE_GPIO_MATRIX) && defined(BOARD_HAS_SDMMC) _pin_clk = SDMMC_CLK; _pin_cmd = SDMMC_CMD; @@ -44,8 +45,9 @@ SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) { _pin_d2 = SDMMC_D2; _pin_d3 = SDMMC_D3; #endif // BOARD_HAS_1BIT_SDMMC +#endif // !defined(CONFIG_IDF_TARGET_ESP32P4) -#elif SOC_SDMMC_USE_IOMUX +#elif SOC_SDMMC_USE_IOMUX && defined(BOARD_HAS_SDMMC) && defined(CONFIG_IDF_TARGET_ESP32) _pin_clk = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK; _pin_cmd = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD; _pin_d0 = SDMMC_SLOT1_IOMUX_PIN_NUM_D0; @@ -54,6 +56,16 @@ SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) { _pin_d2 = SDMMC_SLOT1_IOMUX_PIN_NUM_D2; _pin_d3 = SDMMC_SLOT1_IOMUX_PIN_NUM_D3; #endif // BOARD_HAS_1BIT_SDMMC + +#elif SOC_SDMMC_USE_IOMUX && defined(BOARD_HAS_SDMMC) && defined(CONFIG_IDF_TARGET_ESP32P4) + _pin_clk = SDMMC_SLOT0_IOMUX_PIN_NUM_CLK; + _pin_cmd = SDMMC_SLOT0_IOMUX_PIN_NUM_CMD; + _pin_d0 = SDMMC_SLOT0_IOMUX_PIN_NUM_D0; +#ifndef BOARD_HAS_1BIT_SDMMC + _pin_d1 = SDMMC_SLOT0_IOMUX_PIN_NUM_D1; + _pin_d2 = SDMMC_SLOT0_IOMUX_PIN_NUM_D2; + _pin_d3 = SDMMC_SLOT0_IOMUX_PIN_NUM_D3; +#endif // BOARD_HAS_1BIT_SDMMC #endif } diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index 93c686a0d13..35e52f43e4d 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -83,7 +83,7 @@ void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) { _miso = (_spi_num == FSPI) ? MISO : -1; _mosi = (_spi_num == FSPI) ? MOSI : -1; _ss = (_spi_num == FSPI) ? SS : -1; -#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 _sck = SCK; _miso = MISO; _mosi = MOSI; diff --git a/libraries/SPIFFS/examples/SPIFFS_time/ci.json b/libraries/SPIFFS/examples/SPIFFS_time/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/SPIFFS/examples/SPIFFS_time/ci.json +++ b/libraries/SPIFFS/examples/SPIFFS_time/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/SimpleBLE/examples/SimpleBleDevice/ci.json b/libraries/SimpleBLE/examples/SimpleBleDevice/ci.json index a571a89a877..eb6596c4a37 100644 --- a/libraries/SimpleBLE/examples/SimpleBleDevice/ci.json +++ b/libraries/SimpleBLE/examples/SimpleBleDevice/ci.json @@ -1,6 +1,7 @@ { "targets": { "esp32c3": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/Update/examples/AWS_S3_OTA_Update/ci.json b/libraries/Update/examples/AWS_S3_OTA_Update/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/Update/examples/AWS_S3_OTA_Update/ci.json +++ b/libraries/Update/examples/AWS_S3_OTA_Update/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Update/examples/HTTPS_OTA_Update/ci.json b/libraries/Update/examples/HTTPS_OTA_Update/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/Update/examples/HTTPS_OTA_Update/ci.json +++ b/libraries/Update/examples/HTTPS_OTA_Update/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Update/examples/HTTP_Client_AES_OTA_Update/ci.json b/libraries/Update/examples/HTTP_Client_AES_OTA_Update/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/Update/examples/HTTP_Client_AES_OTA_Update/ci.json +++ b/libraries/Update/examples/HTTP_Client_AES_OTA_Update/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Update/examples/HTTP_Server_AES_OTA_Update/ci.json b/libraries/Update/examples/HTTP_Server_AES_OTA_Update/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/Update/examples/HTTP_Server_AES_OTA_Update/ci.json +++ b/libraries/Update/examples/HTTP_Server_AES_OTA_Update/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Update/examples/OTAWebUpdater/ci.json b/libraries/Update/examples/OTAWebUpdater/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/Update/examples/OTAWebUpdater/ci.json +++ b/libraries/Update/examples/OTAWebUpdater/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/AdvancedWebServer/ci.json b/libraries/WebServer/examples/AdvancedWebServer/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/AdvancedWebServer/ci.json +++ b/libraries/WebServer/examples/AdvancedWebServer/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/FSBrowser/ci.json b/libraries/WebServer/examples/FSBrowser/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/FSBrowser/ci.json +++ b/libraries/WebServer/examples/FSBrowser/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/Filters/ci.json b/libraries/WebServer/examples/Filters/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/Filters/ci.json +++ b/libraries/WebServer/examples/Filters/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/HelloServer/ci.json b/libraries/WebServer/examples/HelloServer/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/HelloServer/ci.json +++ b/libraries/WebServer/examples/HelloServer/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/HttpAdvancedAuth/ci.json b/libraries/WebServer/examples/HttpAdvancedAuth/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/HttpAdvancedAuth/ci.json +++ b/libraries/WebServer/examples/HttpAdvancedAuth/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/HttpAuthCallback/ci.json b/libraries/WebServer/examples/HttpAuthCallback/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/HttpAuthCallback/ci.json +++ b/libraries/WebServer/examples/HttpAuthCallback/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/HttpAuthCallbackInline/ci.json b/libraries/WebServer/examples/HttpAuthCallbackInline/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/HttpAuthCallbackInline/ci.json +++ b/libraries/WebServer/examples/HttpAuthCallbackInline/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/HttpBasicAuth/ci.json b/libraries/WebServer/examples/HttpBasicAuth/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/HttpBasicAuth/ci.json +++ b/libraries/WebServer/examples/HttpBasicAuth/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/HttpBasicAuthSHA1/ci.json b/libraries/WebServer/examples/HttpBasicAuthSHA1/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/HttpBasicAuthSHA1/ci.json +++ b/libraries/WebServer/examples/HttpBasicAuthSHA1/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/ci.json b/libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/ci.json +++ b/libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/MultiHomedServers/ci.json b/libraries/WebServer/examples/MultiHomedServers/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/MultiHomedServers/ci.json +++ b/libraries/WebServer/examples/MultiHomedServers/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/PathArgServer/ci.json b/libraries/WebServer/examples/PathArgServer/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/PathArgServer/ci.json +++ b/libraries/WebServer/examples/PathArgServer/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/SDWebServer/ci.json b/libraries/WebServer/examples/SDWebServer/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/SDWebServer/ci.json +++ b/libraries/WebServer/examples/SDWebServer/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/SimpleAuthentification/ci.json b/libraries/WebServer/examples/SimpleAuthentification/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/SimpleAuthentification/ci.json +++ b/libraries/WebServer/examples/SimpleAuthentification/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/UploadHugeFile/ci.json b/libraries/WebServer/examples/UploadHugeFile/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/UploadHugeFile/ci.json +++ b/libraries/WebServer/examples/UploadHugeFile/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/WebServer/ci.json b/libraries/WebServer/examples/WebServer/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/WebServer/ci.json +++ b/libraries/WebServer/examples/WebServer/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WebServer/examples/WebUpdate/ci.json b/libraries/WebServer/examples/WebUpdate/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WebServer/examples/WebUpdate/ci.json +++ b/libraries/WebServer/examples/WebUpdate/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/FTM/FTM_Initiator/ci.json b/libraries/WiFi/examples/FTM/FTM_Initiator/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/FTM/FTM_Initiator/ci.json +++ b/libraries/WiFi/examples/FTM/FTM_Initiator/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/FTM/FTM_Responder/ci.json b/libraries/WiFi/examples/FTM/FTM_Responder/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/FTM/FTM_Responder/ci.json +++ b/libraries/WiFi/examples/FTM/FTM_Responder/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/SimpleWiFiServer/ci.json b/libraries/WiFi/examples/SimpleWiFiServer/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/SimpleWiFiServer/ci.json +++ b/libraries/WiFi/examples/SimpleWiFiServer/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WPS/ci.json b/libraries/WiFi/examples/WPS/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WPS/ci.json +++ b/libraries/WiFi/examples/WPS/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiAccessPoint/ci.json b/libraries/WiFi/examples/WiFiAccessPoint/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiAccessPoint/ci.json +++ b/libraries/WiFi/examples/WiFiAccessPoint/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiBlueToothSwitch/ci.json b/libraries/WiFi/examples/WiFiBlueToothSwitch/ci.json index 521ae8f5ff1..156dda6560c 100644 --- a/libraries/WiFi/examples/WiFiBlueToothSwitch/ci.json +++ b/libraries/WiFi/examples/WiFiBlueToothSwitch/ci.json @@ -1,6 +1,7 @@ { "targets": { "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/WiFi/examples/WiFiClient/ci.json b/libraries/WiFi/examples/WiFiClient/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiClient/ci.json +++ b/libraries/WiFi/examples/WiFiClient/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiClientBasic/ci.json b/libraries/WiFi/examples/WiFiClientBasic/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiClientBasic/ci.json +++ b/libraries/WiFi/examples/WiFiClientBasic/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiClientConnect/ci.json b/libraries/WiFi/examples/WiFiClientConnect/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiClientConnect/ci.json +++ b/libraries/WiFi/examples/WiFiClientConnect/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiClientEnterprise/ci.json b/libraries/WiFi/examples/WiFiClientEnterprise/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiClientEnterprise/ci.json +++ b/libraries/WiFi/examples/WiFiClientEnterprise/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiClientEvents/ci.json b/libraries/WiFi/examples/WiFiClientEvents/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiClientEvents/ci.json +++ b/libraries/WiFi/examples/WiFiClientEvents/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiClientStaticIP/ci.json b/libraries/WiFi/examples/WiFiClientStaticIP/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiClientStaticIP/ci.json +++ b/libraries/WiFi/examples/WiFiClientStaticIP/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiExtender/ci.json b/libraries/WiFi/examples/WiFiExtender/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiExtender/ci.json +++ b/libraries/WiFi/examples/WiFiExtender/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiIPv6/ci.json b/libraries/WiFi/examples/WiFiIPv6/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiIPv6/ci.json +++ b/libraries/WiFi/examples/WiFiIPv6/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiMulti/ci.json b/libraries/WiFi/examples/WiFiMulti/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiMulti/ci.json +++ b/libraries/WiFi/examples/WiFiMulti/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiMultiAdvanced/ci.json b/libraries/WiFi/examples/WiFiMultiAdvanced/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiMultiAdvanced/ci.json +++ b/libraries/WiFi/examples/WiFiMultiAdvanced/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiScan/ci.json b/libraries/WiFi/examples/WiFiScan/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiScan/ci.json +++ b/libraries/WiFi/examples/WiFiScan/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiScanAsync/ci.json b/libraries/WiFi/examples/WiFiScanAsync/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiScanAsync/ci.json +++ b/libraries/WiFi/examples/WiFiScanAsync/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiScanDualAntenna/ci.json b/libraries/WiFi/examples/WiFiScanDualAntenna/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiScanDualAntenna/ci.json +++ b/libraries/WiFi/examples/WiFiScanDualAntenna/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiScanTime/ci.json b/libraries/WiFi/examples/WiFiScanTime/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiScanTime/ci.json +++ b/libraries/WiFi/examples/WiFiScanTime/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiSmartConfig/ci.json b/libraries/WiFi/examples/WiFiSmartConfig/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiSmartConfig/ci.json +++ b/libraries/WiFi/examples/WiFiSmartConfig/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiTelnetToSerial/ci.json b/libraries/WiFi/examples/WiFiTelnetToSerial/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiTelnetToSerial/ci.json +++ b/libraries/WiFi/examples/WiFiTelnetToSerial/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFi/examples/WiFiUDPClient/ci.json b/libraries/WiFi/examples/WiFiUDPClient/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFi/examples/WiFiUDPClient/ci.json +++ b/libraries/WiFi/examples/WiFiUDPClient/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/WiFiProv/examples/WiFiProv/ci.json b/libraries/WiFiProv/examples/WiFiProv/ci.json index d8b3664bc65..ed63a39b4c0 100644 --- a/libraries/WiFiProv/examples/WiFiProv/ci.json +++ b/libraries/WiFiProv/examples/WiFiProv/ci.json @@ -1,5 +1,6 @@ { "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 701e77b3b21..21b3635bfcc 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -460,56 +460,42 @@ }, { "name": "esptool_py", - "version": "4.6", + "version": "4.8.0", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-src.tar.gz", - "archiveFileName": "esptool-v4.6-src.tar.gz", - "checksum": "SHA-256:22f9bad0cd1cea14e554ac1f4a6d8f67415ff7029a66ce9130756276e7264e5a", - "size": "99141" - }, - { - "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-src.tar.gz", - "archiveFileName": "esptool-v4.6-src.tar.gz", - "checksum": "SHA-256:22f9bad0cd1cea14e554ac1f4a6d8f67415ff7029a66ce9130756276e7264e5a", - "size": "99141" + "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-linux-amd64.zip", + "archiveFileName": "esptool-v4.8.0-linux-amd64.zip", + "checksum": "SHA-256:e637adc204b74b980013e89dafce6e056401ec26c94e205b0158075a836c56c6", + "size": "64617780" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-src.tar.gz", - "archiveFileName": "esptool-v4.6-src.tar.gz", - "checksum": "SHA-256:22f9bad0cd1cea14e554ac1f4a6d8f67415ff7029a66ce9130756276e7264e5a", - "size": "99141" + "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-linux-arm64.zip", + "archiveFileName": "esptool-v4.8.0-linux-arm64.zip", + "checksum": "SHA-256:c3a7749bed8d1929b0ad35743cc5557d60ecb81a10ffac28cb55ed1545e0223a", + "size": "54432155" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-src.tar.gz", - "archiveFileName": "esptool-v4.6-src.tar.gz", - "checksum": "SHA-256:22f9bad0cd1cea14e554ac1f4a6d8f67415ff7029a66ce9130756276e7264e5a", - "size": "99141" + "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-linux-arm32.zip", + "archiveFileName": "esptool-v4.8.0-linux-arm32.zip", + "checksum": "SHA-256:b781a86b53a17d24e02996c0a7958f9b76f6873fc1cc07c64ab6326e19395570", + "size": "45858426" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-macos.tar.gz", - "archiveFileName": "esptool-v4.6-macos.tar.gz", - "checksum": "SHA-256:885ec69fcffdcb9e7c6eacd2589f13a45ce6bcb6742bea368ec3a73bcca6dd59", - "size": "5851297" + "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-macos.zip", + "archiveFileName": "esptool-v4.8.0-macos.zip", + "checksum": "SHA-256:73bba755d2da15ef18b8b8d8fe37c459d296648efb02d5449a3fc0035930306a", + "size": "29821710" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-win64.zip", - "archiveFileName": "esptool-v4.6-win64.zip", - "checksum": "SHA-256:c7c68cd1aa520cbfce488ff6a77818ece272272eb012831b9d9ab1280a7c393f", - "size": "6638480" - }, - { - "host": "i686-mingw32", - "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-win64.zip", - "archiveFileName": "esptool-v4.6-win64.zip", - "checksum": "SHA-256:c7c68cd1aa520cbfce488ff6a77818ece272272eb012831b9d9ab1280a7c393f", - "size": "6638480" + "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-win64.zip", + "archiveFileName": "esptool-v4.8.0-win64.zip", + "checksum": "SHA-256:5575beabfe8c1c1ea7c1a0f1bd42ee97ac3f4c4dae5fc74cda58be0e23016da3", + "size": "33608471" } ] }, diff --git a/platform.txt b/platform.txt index ebc8d23a5c7..b9c31d4337f 100644 --- a/platform.txt +++ b/platform.txt @@ -10,7 +10,7 @@ tools.riscv32-esp-elf-gdb.path={runtime.platform.path}/tools/riscv32-esp-elf-gdb tools.esptool_py.path={runtime.platform.path}/tools/esptool tools.esptool_py.cmd=esptool -tools.esptool_py.cmd.linux=esptool.py +tools.esptool_py.cmd.linux=esptool tools.esptool_py.cmd.windows=esptool.exe tools.esptool_py.network_cmd=python3 "{runtime.platform.path}/tools/espota.py" -r @@ -84,6 +84,7 @@ build.extra_flags.esp32c2=-DARDUINO_USB_CDC_ON_BOOT=0 build.extra_flags.esp32c3=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} build.extra_flags.esp32c6=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} build.extra_flags.esp32h2=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} +build.extra_flags.esp32p4=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} # This can be overriden in boards.txt build.zigbee_mode= @@ -101,7 +102,7 @@ build.code_debug=0 build.defines= build.loop_core= build.event_core= -build.extra_flags=-DARDUINO_HOST_OS="{runtime.os}" -DARDUINO_FQBN="{build.fqbn}" -DESP32 -DCORE_DEBUG_LEVEL={build.code_debug} {build.loop_core} {build.event_core} {build.defines} {build.extra_flags.{build.mcu}} {build.zigbee_mode} +build.extra_flags=-DARDUINO_HOST_OS="{runtime.os}" -DARDUINO_FQBN="{build.fqbn}" -DESP32=ESP32 -DCORE_DEBUG_LEVEL={build.code_debug} {build.loop_core} {build.event_core} {build.defines} {build.extra_flags.{build.mcu}} {build.zigbee_mode} build.extra_libs= build.memory_type={build.boot}_qspi @@ -121,7 +122,6 @@ recipe.hooks.prebuild.3.pattern.windows=cmd /c if not exist "{build.path}\partit # Check if custom bootloader exist: source > variant > build.boot recipe.hooks.prebuild.4.pattern_args=--chip {build.mcu} elf2image --flash_mode {build.flash_mode} --flash_freq {build.img_freq} --flash_size {build.flash_size} -o recipe.hooks.prebuild.4.pattern=/usr/bin/env bash -c "[ -f "{build.source.path}"/bootloader.bin ] && cp -f "{build.source.path}"/bootloader.bin "{build.path}"/{build.project_name}.bootloader.bin || ( [ -f "{build.variant.path}"/{build.custom_bootloader}.bin ] && cp "{build.variant.path}"/{build.custom_bootloader}.bin "{build.path}"/{build.project_name}.bootloader.bin || "{tools.esptool_py.path}"/{tools.esptool_py.cmd} {recipe.hooks.prebuild.4.pattern_args} "{build.path}"/{build.project_name}.bootloader.bin "{compiler.sdk.path}"/bin/bootloader_{build.boot}_{build.boot_freq}.elf )" -recipe.hooks.prebuild.4.pattern.linux=/usr/bin/env bash -c "[ -f "{build.source.path}"/bootloader.bin ] && cp -f "{build.source.path}"/bootloader.bin "{build.path}"/{build.project_name}.bootloader.bin || ( [ -f "{build.variant.path}"/{build.custom_bootloader}.bin ] && cp "{build.variant.path}"/{build.custom_bootloader}.bin "{build.path}"/{build.project_name}.bootloader.bin || python3 "{tools.esptool_py.path}"/{tools.esptool_py.cmd} {recipe.hooks.prebuild.4.pattern_args} "{build.path}"/{build.project_name}.bootloader.bin "{compiler.sdk.path}"/bin/bootloader_{build.boot}_{build.boot_freq}.elf )" recipe.hooks.prebuild.4.pattern.windows=cmd /c IF EXIST "{build.source.path}\bootloader.bin" ( COPY /y "{build.source.path}\bootloader.bin" "{build.path}\{build.project_name}.bootloader.bin" ) ELSE ( IF EXIST "{build.variant.path}\{build.custom_bootloader}.bin" ( COPY "{build.variant.path}\{build.custom_bootloader}.bin" "{build.path}\{build.project_name}.bootloader.bin" ) ELSE ( "{tools.esptool_py.path}\{tools.esptool_py.cmd}" {recipe.hooks.prebuild.4.pattern_args} "{build.path}\{build.project_name}.bootloader.bin" "{compiler.sdk.path}\bin\bootloader_{build.boot}_{build.boot_freq}.elf" ) ) # Check if custom build options exist in the sketch folder @@ -162,7 +162,6 @@ recipe.objcopy.partitions.bin.pattern={tools.gen_esp32part.cmd} -q "{build.path} ## Create bin recipe.objcopy.bin.pattern_args=--chip {build.mcu} elf2image --flash_mode "{build.flash_mode}" --flash_freq "{build.img_freq}" --flash_size "{build.flash_size}" --elf-sha256-offset 0xb0 -o "{build.path}/{build.project_name}.bin" "{build.path}/{build.project_name}.elf" recipe.objcopy.bin.pattern="{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.objcopy.bin.pattern_args} -recipe.objcopy.bin.pattern.linux=python3 "{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.objcopy.bin.pattern_args} ## Create Insights Firmware Package recipe.hooks.objcopy.postobjcopy.1.pattern_args={build.path} {build.project_name} "{build.source.path}" @@ -176,7 +175,6 @@ recipe.hooks.objcopy.postobjcopy.2.pattern.windows=cmd /c if exist "{build.path} # Create merged binary recipe.hooks.objcopy.postobjcopy.3.pattern_args=--chip {build.mcu} merge_bin -o "{build.path}/{build.project_name}.merged.bin" --fill-flash-size {build.flash_size} --flash_mode keep --flash_freq keep --flash_size keep {build.bootloader_addr} "{build.path}/{build.project_name}.bootloader.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin" 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x10000 "{build.path}/{build.project_name}.bin" recipe.hooks.objcopy.postobjcopy.3.pattern="{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.hooks.objcopy.postobjcopy.3.pattern_args} -recipe.hooks.objcopy.postobjcopy.3.pattern.linux=python3 "{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.hooks.objcopy.postobjcopy.3.pattern_args} ## Save bin recipe.output.tmp_file={build.project_name}.bin @@ -286,7 +284,6 @@ tools.esptool_py.upload.params.verbose= tools.esptool_py.upload.params.quiet= tools.esptool_py.upload.pattern_args=--chip {build.mcu} --port "{serial.port}" --baud {upload.speed} {upload.flags} --before default_reset --after hard_reset write_flash {upload.erase_cmd} -z --flash_mode keep --flash_freq keep --flash_size keep {build.bootloader_addr} "{build.path}/{build.project_name}.bootloader.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin" 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x10000 "{build.path}/{build.project_name}.bin" {upload.extra_flags} tools.esptool_py.upload.pattern="{path}/{cmd}" {upload.pattern_args} -tools.esptool_py.upload.pattern.linux=python3 "{path}/{cmd}" {upload.pattern_args} ## Program Application ## ------------------- @@ -294,7 +291,6 @@ tools.esptool_py.program.params.verbose= tools.esptool_py.program.params.quiet= tools.esptool_py.program.pattern_args=--chip {build.mcu} --port "{serial.port}" --baud {upload.speed} {upload.flags} --before default_reset --after hard_reset write_flash -z --flash_mode keep --flash_freq keep --flash_size keep 0x10000 "{build.path}/{build.project_name}.bin" tools.esptool_py.program.pattern="{path}/{cmd}" {program.pattern_args} -tools.esptool_py.program.pattern.linux=python3 "{path}/{cmd}" {program.pattern_args} ## Erase Chip (before burning the bootloader) ## ------------------------------------------ @@ -303,7 +299,6 @@ tools.esptool_py.erase.params.verbose= tools.esptool_py.erase.params.quiet= tools.esptool_py.erase.pattern_args=--chip {build.mcu} --port "{serial.port}" --baud {upload.speed} {upload.flags} --before default_reset --after hard_reset erase_flash tools.esptool_py.erase.pattern="{path}/{cmd}" {erase.pattern_args} -tools.esptool_py.erase.pattern.linux=python3 "{path}/{cmd}" {erase.pattern_args} ## Burn Bootloader ## --------------- diff --git a/tools/get.exe b/tools/get.exe index 161cb193cae89e3dbc84006a7c7332e2683eb329..2082c7a4b68b6438c4f43a736a9d1b6aedda614f 100644 GIT binary patch delta 152918 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
0B%e@fJaaId;=?OP_rRCmU`>SnfAUEcPoi=C;m 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 jB}uuzAZIuX47bF&4G{z2IcTLUJ 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ℜ$EH)MSXX$(^NI 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%0Dd72Ui-D$l^nLdmVR=SJ2NH4=G3onat?T{)=}bV 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 Ry6u*mCZ<5$`OnXr@qdjDlHLFS diff --git a/tools/get.py b/tools/get.py index 45f97d62f54..6f42cbaa577 100755 --- a/tools/get.py +++ b/tools/get.py @@ -177,6 +177,7 @@ def is_latest_version(destination, dirname, rename_to, cfile, checksum): def unpack(filename, destination, force_extract, checksum): # noqa: C901 + sys_name = platform.system() dirname = "" cfile = None # Compressed file file_is_corrupted = False @@ -223,6 +224,8 @@ def unpack(filename, destination, force_extract, checksum): # noqa: C901 rename_to = re.match(r"^([a-z][^\-]*\-*)+", dirname).group(0).strip("-") if rename_to == dirname and dirname.startswith("esp32-arduino-libs-"): rename_to = "esp32-arduino-libs" + elif rename_to == dirname and dirname.startswith("esptool-"): + rename_to = "esptool" if not force_extract: if is_latest_version(destination, dirname, rename_to, cfile, checksum): @@ -256,6 +259,11 @@ def unpack(filename, destination, force_extract, checksum): # noqa: C901 print("Renaming {0} to {1} ...".format(dirname, rename_to)) shutil.move(dirname, rename_to) + # Add execute permission to esptool on non-Windows platforms + if rename_to.startswith("esptool") and "CYGWIN_NT" not in sys_name and "Windows" not in sys_name: + st = os.stat(os.path.join(destination, rename_to, "esptool")) + os.chmod(os.path.join(destination, rename_to, "esptool"), st.st_mode | 0o111) + with open(os.path.join(destination, rename_to, ".package_checksum"), "w") as f: f.write(checksum) diff --git a/tools/platformio-build.py b/tools/platformio-build.py index 1ece3afddff..485879944eb 100644 --- a/tools/platformio-build.py +++ b/tools/platformio-build.py @@ -213,7 +213,7 @@ def add_tinyuf2_extra_image(): LIBSOURCE_DIRS=[join(FRAMEWORK_DIR, "libraries")], FLASH_EXTRA_IMAGES=[ ( - "0x1000" if build_mcu in ("esp32", "esp32s2") else "0x0000", + "0x1000" if build_mcu in ["esp32", "esp32s2"] else ("0x2000" if build_mcu in ["esp32p4"] else "0x0000"), get_bootloader_image(variants_dir), ), ("0x8000", join(env.subst("$BUILD_DIR"), "partitions.bin")), From 87c0e7763da8838a4af19ed1196632882e25fea4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:19:40 +0000 Subject: [PATCH 012/406] change(tools): Push generated binaries to PR --- tools/get.exe | Bin 6943192 -> 6943192 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/get.exe b/tools/get.exe index 2082c7a4b68b6438c4f43a736a9d1b6aedda614f..5a1d7b8e90bdfc4b62f4342528b68561dfeee102 100644 GIT binary patch delta 38672 zcmWjJV{oQD7XaX`t*x!CZQHi(t!>=JmTzriYnxl!?Y3Lnw*5Wdk1LazoJ`InGiNfH zEbo;w^6sc&jcLgl^IQ$HH5SAwVEOpg^EOU_f9& z;6UI(5I_(?kU)?@P(V;Y&_KR}po3t5V1i(QV1wX*;DX?R;DZo=5P}ea5QC6_kb;nb zkc0dHp#Y%-p#q@>p#h-#+YMg0p6`Rv$hXdPf^;*-`W(O=?m{DuSbImEkof&R^ z$^WVCpllklEHOJ4U-r1cVt9tZ_{;n2PyV>lTK*C`NAOV+e*Yr@k&%{T$#fuj z4c6<)66u2$95u-R*18N~u1dOEqM8OvPgPY@=l90nS|e8SX)hEh6=Ue7vQxSAf2?+! zWPYeM?5kmUF8%|`EiEU$G?R$9IyOG&FjQ>sXsVTZKEu5lKrw%d@sZa8Po2KAxGff=HB zLa7+Z#7oCWu+$)v?M8NHu1SY*_Ti?%VVd->j`+(X>L30jgN1# z@;+N3DqVB1N{x0Z9@4RH#lHkk8jbnM9HO&2#`B0DDw#hf@yH(N=vY~ptHtSl5W%M6u+y^BNV z*(UVnPv}nTC(qli2ivZb+phn$T{pE|yQK(0bGI|Mdc7voSeBZ04f9fEj5WGaDURp< zESa3v01lFpwLDlq5>O~|d7D!{VPUgXENe_xcqv;=8l$bPl6L?OKeZyt-qUU0r;wrL@QGtFAhboEq0ui0A9 zZq+8Fr*wD?E2E{%`p>cL?Ew>iwRu+}RkEE*gXWke#S@*k__$n*s$r+-*v08ap)8Sl zgW~ulV3pED?X5qiNiies%~2wL@M06J zIOtME*=!Lh_C3Y>{M3E;%#bQ3G8~y%Dt|`?s=Bl8{6z(Xno=|tj*Y;!;)K`PUldc?%jZ52D%i(hc?+B-G!&^ z(}VR`%5o_Od*iOit;ztNwnLMYOOwUQHo{8c?N_0)-85GrCan*kZAax&iqYzz`aK7b z_4I0-6XR+vdzxX;xWZp_5?sHmtljev>b+PQo}qj8UD$%D0fP4yp8c=y3H3Mq*O575 z!ySOIH;spxKBUtZW%&cZyifxDd~+Q=Qrx z(5ifK-ZxxO3a?fDxcQtb)zRR&;&RwKD%HNSGMFCU;;6Ce3g2t3V?1~ce}1tE2uRE$ z-ae|XnsI(-s6uh+)VNHk@^pUhs$wA68th1Y;0$nFNLp*Yr(MJ(=t;<1x&iL?-u=+e zII3D3bPpU3kC3WZVp~tUa`y1G9gVxPwj6h@y#V=;MQb#*W|KRzJv6;9!-Mz`Zo_k5nN}=jcouQNJ7k36B z*B%bRi5pFxm@570IXdlXXJE&Nv3WS>Z0zjpL(=xW+OPV>a*8R}QLg%BY7b-2&y;@) z&pTkytJ8En7w5?=`baB!q%dKPc<(0KS!l4Wi^Y~mcV_W@&mC>go4D~1d*%<$ObE`C z9Jy`ukyZ2>?%o4h;~`q@JkCs#q#|fj*)0!d?pTNK$cFcD_X6zpfybe$cdvE)_H3M) zMw} zJCV)!9Zk=PO*;im`9VPeLtcWzUO6MnGuMLG0ntl3(MLwnM|%HHd`V%FcI(ut2DFGy zVG2|2Q98#bpdTk$V?`b(MINVA*!)@b;85*axuFT@eh%Fd^Vi}zYJ|7>rr4?WXKfSO z#G}-xCcTAJ+bAPzXMNgejD<{iv-!)q&+QyliB0$uI1+-Zo1v_ah8OU8CmBp-z1?Cd z){YCk$DekFw3hercP5}HG5C#Yk3FmohnHJ<&HG6M3b6y7&nR4Fx3SlUPTM-o(n8BM zyl1nS&^24|({U(LYeajG`a=gd1+^zWj7sjW36<)f;SQP~F2AsM`YKly`}LfwCMB)vtRHK*R$cO>@gi4D)M=gm01 z=kPPqRlnrFUXc*fBC~H5Pw(3>cKc*y{yM$9?w53bXcHNqs2I8uEVf+!v$n9XJ;b+Q zFEJF*DH*dSMVCDP`rJYpt99{yjMvO9s9QP=TqWsg-uQBC3E8PUd|j((T*YyfAH}8V zoM^fFD7I=WobD}*d;7VCjvp1;zVK~U2^ki2zx{+L-4olFqDylQ7{?9pLt65U>45Gk zbKqdwsLs{?XMY@ONmE;vwL(`xY}h6>ZrGf;rM{HkMVr=zBD3OI{N0^vwN*c|gY2RU zP>Sq8z0`QB_Ma$9Kb>yV+L(N-m{=2ZuV>R(^j)~Ht*uxQbYEM03;eFp=zrP(3Ltp` z1sJ+pt$W7!s6t(+O|4hH&v#cY%tLdiXws;p04fSuY3lAqs;zTr>LN@PnO$Bvr$p|A z8-=fSGYqm0nhm;L`3-36aWtQ3uX@^g+N})^mIgDclN~V+ zf{WqW#3ugP?i^>5i)-4%#{R(%4vTc!S`7}y{_*aFXM|N*+Ii+0=r>S|0RWwr)!9YW zQ-h0#AH!Bpbx>YAUyBQi-j&ILjora+%jV?x)DEG|m*%CU;n-X2=GgecMo08R0At$3 zR!8;&ZPijH8xNhK-i$h5N~kGMfvAn z)M_!-nc@MtN5xj&xjMRk8lZd2xA1$dJatg9dDWw$_>UUHjDZdBh3ZC++RM6u4Y0a3 z*)=zrRF>genE})F|CUONEl&3iOOt5oFkHvGfkS9~ylZVTsX0TcK11qH29?HLN>yC_ zZPm~2+y|RQd>suoLp8Z`j%FMqHOBo12EE~Q8mNG@C3F|5IkW*_=LyfjgK~y5SnxHZ zROh~R$-zoB;0K~i0&pmCV*w_6DqmhU|G}zE1oxNtXGXc}1Mf>|bb{jOoR4sBLUinm zy1b7L2~KPq*?sFZ4W=BTNY9bdnCl(!_)IO*DbdT4p*2O&_V)pbui&4lBTWCvmkRk6 z0dyroMKk~5l^N**Ys8!xV|U;pujCc?qCK!Ad@t6;uceSyHas79;1U#5b0MTk*F;$* zJV|%$449J2A1s;)ROhi}zi2Qwdre=_>&@YhoBQ1FWpo_|E8*Qr4xu1?v=4bk!~pFi zT~v6O6vVurR$Kxx>21v#3?1QfhFx=hu8s<5nVrArjNEA1@Y z80jReSo#=(z&({+$p+n**nT`3XA<_A;bii*!#K}h+vkv4RS|$ZDHNA5TZS@ilAhId zw9~#6C?OU5dd9Z;lx{DYzJ?MXw9QsT*sTOJI01U%@XXKb&MeQYl%%EWZe~#6Xy97R z^=_92*sd818U zt@6$5D=8h{JpCf}Eqbhbs(a|orkbW16DIz|jeQnu;{CqsVyhs{NBed4 zofmNT%F7I@^>KS2e|@1WaD7!8TKlJT`yrMsw6+L*HUhn6z?_~y_;MJPhujPHtzbIy zvyjn8+^fxK&-Fsj-pncF6W~kuxfQTT8S(YV`(7#ZL`naQ-ThjdeexA6REe(tWpVK} zqxJQ23Yz!zdaB%?51hSzT)m$<_4fkkJZ?)j9*MvHC*g(&s zchw#eg9@ivhKu-$^DB~llri-38Fbwe z?B4!jK}7{H=o;(Zml7L1S^bB%fz+l`dX$Z;nk-$ajX}!ddAaU-w0Re>{^Dsd!vwKJ z=Oo~yE`b(h9IJ|aRW*4$Jwb4}t^(NV>X^Z*&QG39BY;lR!w@D}RZo0h()zcrgxiYQ{!_3eE3vajOT#Ak|Iq8vwW zhB$y|4mk*sum8R%lJFX+6J9l7dMw5`XZq}KpOlh!97I4SEqP8pnm{By%nP^)lm65^ zr#epZr;Cjkfi=AsksR8Cd{HGfmybr@|4D2vNf$R7D9lfgt}iYIEr@j zLnQYy1ZP(c(z^u3McprhWaN!xWKa!~=P!)6F27iOl7IZ(E~H5AMMyTr%=di^VMRUk ztSSTnsM&eb#QY@xD*>u$)O~OAYiS(&=OcwzfR29HQEdbi0oaBYl;(6KUEQq&4sOXtiScIB z=s@R@3Q&bTh&b6nThllCAG=GsB>b)hj<<|{>+(iz)CvVAiIs^0=w|F!7Wq3pM1v_( zFK~(U%p#B=>V``^RBs?nYUb zVty(;Qv^d(W-R8Q!vbJ}YAE1Vc;NN8+hO%^<&_7vaHwCd-o~0$>$XLMQHr3}9@?+Zg43fx-}|$h zHIL44Dvegnm8%9L>g8m63^_kJFOyF3=x__RRK4bC%gf&(01w#IPxl6E=}~J-$g1AA zv^wgiNO;bCiM8#qwZ9|LF<>dyd7#HVp1aj;FtiYejTuM@w1v-E`_6u4$#3!B%eX*G zpP|;NS?2D|LNfm_#(PgezVc;Y;oVBbCWdItrLJ3?gr`8qNTDxT2h|O-sRE|eYWWfZ z!cuhQUHjTgSsswp(H!qsS}v55$2d8CxQgqO$+&-e_o7(1^T~m9nRJR0^>lB!z<3HH>SZ^}; zcIhaFtn~DmadvV~tp%}v9-dNei5LEjvbU5@zWAU&wUrk{XuYlbMp46oUlWrI#nO7R zY?!a9We()8x;yGo+)k8Fv&%uU?5E1n!)7&(=9|<-4eM!&-#HJmO6-@U53}d)-X3)Q zutw7n`0+AMiMkI)`jl*aFcn#Qhtv%Qe^6Q3G5MMu(w~ytO#cG5*`3R}&E@Dl*Rt7w z=s3jc5IVR&Lpu#3U&i$ptAJU zoZ46vy$%24O2=GCP zmH*g8?6Bm!sg=lxk_@6fW@Q6Sc}uL8T=`g|)Dy?FV9E`&B#%7GbBx<63D7$swG;Na zsdIpa%y_C$-C)F#qhA_TICWVFY<;s+nq5(cft*E&pHPvs+9NJvHRx<)?g)||&l^E7 zZyv+Y4fsek?TuinwNt;XNs@Kzrk;WkOBv2MK&nKN57zxhvVml=>*YV zX(xHmV4~!}=)nKh<2oTb^jhJ&AUpfp2TB8pfgOJg_3XGE?@eLeX{i{Yi zzQGLIVsMbVj7f>5$txODN*~%Hp>y5C5h>=i?3a zq<~6^7WH3<^18)lcSG^I+Ikg=4Z=AA#SoZUTsq-!jGAyDR{7M(G3n~LOP0YavHl4l zMeM(9Il~B9_0A#){azAS38sY^&E@dNVZKVYNc+|jh2;(+LWX>%xyZ z4R29Sp+yd<={#3d)Jh_vI`G%L7d{!Co9-0lAvr0sZ_7;oqlUC9tz*U2KRL2WG#I?^ALf@H>1F7f7*Pt!tT)0N>nJ4u2L!}X<;VXyqhr^U09^E}H z-8PNh^c70)NtO|$;%a}h{?1>VAO-bK%=t~Cz?s%=RHB1JS1ow8ycu%lV2MA#D;0#( z>&48_$?i;~+MZ}FacU1#ZEH9}F;B$Oi?x}h!{>0}4Z+o}PW?t$2(E<%9QcG3MBS%B zs2zVC6TUA^ZvfSmPoPYB>3e1aWP;-L6FN~=7>?-4Z(V}pi5XAByA&=q9J>Gmodw5% z3R_gJzZRcWtyyNv0&Y-xk zpXBoGg5G1+>Ix%W{44(0Eh1?X{4HY} z(IZ=Cxp;?cxral{%)T8cs~uwiR8;sM=e|(dCX{DN^Brcj4Rf-V@dJ*3wnm|dU2O#~ ztD3vH4JjBM5nFrsnQ5y4-tY4dMDwe9q>Z>2yw1DsTC+zY%j<4MGrBG_TRPjuMIcQV7izMHm|V7B>L^y&b>sDP+Ijhm9T% zVxj)@dyJxD{`tR51C)EzQW7i)z?y?_Qo=1etZFNE;>z?Zu7GAl!~;_s>ZqMz#5E*= zkuU|BP^4tOayCekdELK-boN}MfMr{<7)Svm>xm^KW>u4wT!vTr!gc9ml<4sXbblae zrOGu$zV%>q#Hj&sZp1!P8HlWilLwhn{NwwOTdIF?H_bdnayWT-6CZ5{U)NHb(iV}{ zhQR3u8&=6#32Jt5{|h?j6i$kfkdA}AM_gmOrVh2?);-(%@x7|Gvv~Z)Rpk4X6_X}b zb)E00ek(%Z^z_ftH_@Tyv=AKkfwj9GQ!A#HdBWuNF-JSV?yL;X!M6T1ov|zs3A65= zz?TIF`A>?jSd+01p@02}%)Qwyi#Z7bZkv{*@u9c{RQdV%G1cf4`z=?hv~#M(JLy;b zd#f_)79ln4I?W>5V5Rwjv2(5PMb-0pAo$~?-(}E-?7-24dhNG&*ne~I5z<{F`z%!z zX4UmQ;AHyg#g-5HWTu0TUJYgj^W9%bZMt!tePm z!_1^#-?OerFKFthPTC#UHsQY|&~B3*JEtKWXip_qI_M0n8BPmWN{!~9=fl?0bJ|#A z74PQ(NEq+`l@UFXGM#dtKBwX(TBe3yb5mQ3$sNZxxodW4cHc})f z&@h*hJQ`st$*a({)8EmW5VSMZvy#nVc&BT8J`8o$d}2K=WII>JvJ7A2g`H<- z$NL8X-|=Vs%=R+u4L&iaKW*(gkmYlS4~@iDKDi!MW^WzqUe>_gWfGkdP7ABhr$#q~ z#rN(hjroO`jsb0S!6`k z;a%~lXPboGgDk7uNZnD%W(n3F0`v0{r3wguK7ThT0>bw;jm7|naB6iv`d}U<*K*dV zX)%LSI?Jm8)1Kp`u9EjG+0tas#-HO^^z;W$K3YF`@l5_koQC&hib!h~8p;cQdo&f@ z`t|Q}Dhb~i_Ugt$+npTDgzu8-l0^t>layfVhV++Et=+NhvK)cvf(+JIVMy7aHrW>j zkR>z_hKw#Wuu1($^qU)fzr{Ros>cl@?A;UqV=i08P5Q*->KI(~HrHuE3;bB^9UEi#T%zOc&Q?u&LX@b-=$m{?GZvl6g@ zcyfLvmH$M&AiMUh?@7G4Tk|dw=4aDQKzMR9zU zijX5i&R^pOO_D?zW6rEigbq*juyP-lS)TC{KOduzFYgNota8xXH>@@;(3J?o0lV== z+eNsg>zLA5zHM0o^}FMC%XUUoKkyk9r3CodXk%`~w0+*Qi2{i-f$Z1^-9b6onFNA# zZX8arfiM=Qh~xm9*|?W?qL=|hX~ueNjUQ__B$w=|X)MLEjCz~&_oNab?<-kIe`&nu zSZ$X`CPjRRiolq~V0W<-_Z7LI0A%vaCPIY0H`7IIK*fh2N({ zh_Q3v3U5V_hxcXfiOWe=oWmG-mPj_Wb%Qb2Ni+F3;q453Fh{=Q@arsN{Q39Fl=%V6b1#i>-65&c3~>_OrN<(W>{3=I2(u=+v1Q01i-W?I}-mEKit37xWOtZ;LOGn5sldt zuKb-G9hA-tA-c&k$&vk1nl~F)>QLI~nVu8+G}T?d~-e$Yec~XA-`=M@;=f?(_l4HyHq3lV>iqjP4W= zB`}s7+&H2C2*nKq#Wa|mXQ2FhS9z51AjsvvAT%SlU6rEEyUXoX63Eb!RPy6@q#l>p z>gsSBV9*%PCGJl{X4A(9)Dig)HT^v=Pn&!{CtqluY}$9*5ju}ysjLfE(etX0)nTX^CR5 zMVuYcE*vxn1s@!ov9xC2xu`h^1jb^2RP?kPR>PP%AO+U-=_(nz#46=xIvLgYiX5xb zIk?+TGNj593I8{sW{CC8<-cZK3pP*w7s@A5Lz*{3W*5K1)pziR7S%9I?F_NFNA0BrQn8C5Hrlj3>2hL$R&PDok?`pE zS(;ofJ{ev(-4LqsQ;k*?WbksO-1V%hKht{IEr;+dS-#JPD_6w>yeoE)G}M9&JQSYW z2yVPsxwZ)K+jWHQ(hDhenrgJq%5&k^c;_JFERAs*gVCtn=jL!y)MRJXR;y-9Kf;Y< zziei&a~xqEA}W%=8Qtfs`5BLU#z(&_OrOFfDn&Mk2r@5FUs=!_5hbdUx>ynH_b_-7 zF>)?=u$V{zn4QvplXT02=QTttp}|J_Pw=6mG#HCOWtCyy*{A4^VwX0WqX%ZJQGpm+ z7Ge%c--q{mpyY1UrH~wx7j)1dapamJVc1PzZK>`BP*QRc&J|N@^qj3=MZC%0-F?lI zc)?z_kLLeJloSRJtC=FG5?U-j0a1bj?RqA=45 zjRLGM{_@zsCMsJh{XaV4Ou>GFMVL7^p))H8r-0-xq>e$LW z*+Q_oea!mArZ6j{+(OetR^dB{4OxUicQbWV%Sk`}=9w~P=NTIrOUYCSO~odt17ZFN zMX%1BWW}#=+{6|$4J^qgcG(Bpe$fIWl)&~oBHtM0&b!1TGT)G*SZ!=$Z3Ejmy?#s` zINwNac%{lCW0omX?*g2rIrehe_Nh+GsG+%0SS5?5DO3G_P8`#W_0~TbMi?9EoC0DE zESLtogHI;L6Ne2=mh%6}Jkq|w^XHheopW&KnKqvDW-B$~pSyGCnYh{!OS540 z>s-Lm7n#3S!T9`S{fShzUWIYx6A9cpw`zkudcS+c;w4shoVowBMSG@ig0O+mNa6rj zH@2+oK1xl~Cl&{PoG>#}2R7(lO_h7wK5XVTC2@JdE}#q}Y;^u^{Sd)Zm$NnG{vNG* zU@P~nwoQ^J0$&pL#VL^LI?rf>1awA}t>fk(2Wr28Z^o(%hvI&mEMkurg2Pt(8a4rsTKWKJ!SX7PU=>_8eJk3J#TpEN!m zeP3WsN)t@jR_F87mumA&iuqEQ=@%*PX+eEa5DO1!v<&l)=C$if`N~B)Ww9Z=R&?g9 zZ+!WSqx2dTLD;xu1dWAaGz$=@@KUnaQa>vn-9H^F6PI7jx9YTS3&ZP;BDX#+1$@M{U0 zpGYCN%ymcj(Cc8|S`?tQ!yv-)I?T#se^y)WzES)%!32041qWX__17wO+FXt+;!IWo zEP;qEyl+lOm%>y1f?gdc-%>xkAP%iMHqs~CFNfIYm1Gi}X_+OY_Ib1^ETUpz|HcCi zk|JA-Ap$a(lJgfNM_J$BYYSsoNv2uH%W5R+-1Nv314|+zM<(%Cg~ycj8Oa<=v^I7{ zIA;|T)Ow#NN5r;Sa{0)LDEw7je3?=quA#R5=o$2P(CXS@DMP@L> zcIk^d|M^hxGaUCj$Dkj!bze)+TM+;g7!eJ_8UGiIq{5OoG4b38TTC|nGAR+zx)vji z|6Z>r{7U%HU9#&+xNvg#hsoEp!y->42sU`PfvS_99U$sCyIDkx9*p`H7zsy(dW|sM z6$R6ZKcwJx_(RmMDMNrXOAzdwf1-2fmG%1UU=*@oFFb(|LnXiK=!Odo)ylU{9_Aa} z+HzkIX_m4Zg7F-IxO9_YS`#ubTt3w66j4Y*h2|lCr*w4Cn?%%(S?5Yu9rPRVfG8FT z1`ENAR@_EYRxLYS)Sz;d9$X17KWaRof9MYz*c1E}WGA_{ei&K>T}rNrdNz1=JeeSryK$Ppyx2HD$PA1lS5!&?QT}+wAn8AB6qi zWVb%v;G7UiH+He@jYSLri$P;=4Oq@^<3@`_TEay-@2ap$EgE6T6t#6>TUHQj2Bv7vj4u90S1=|lvEHIglgv-sXb)j0%wEgOS45jQoS0!> z0g-UZt`stk=n>P3h_mgBFOA?}T|5fb%6|z>x1UJnLS_OE-*8ngZu+gdZjKjSw#pkE z_Hod`XumV)5$A*tc!%!abKkw5cV*Lx^m{f%{6UJvx{SCikRZ`7Dg8@at)J0-R|&fN z*UVRWBDJho?*YutQE$rjWy9oVydakA)6TCyR89~Y9Z(GRSkN$gkdJFTfkyoUOpn`b zSbjtm?`yx-DpJ7(T+L^;HPWIo-OjPiM_Qb1z=BX{`DpX2NMfn~Q!=h_E$EX*z}G}& z*&c^9KvC&6%}=nmN-QYri)oz{)W-z_V@*30(x*nGB7ZP1%8mLrpWtJeh9|5q3AAg8 zK@_G_Q};@X^pL`!w@bw;5zWA@?)Frpt_{>AYUwrzfBq3D>+9BIC@e90L!d}y%T$n8 z9?f`u*lg^{&(DU#q!CePMUDf9KDNjC)?k5u$kF5hX*790x`KTUX30Ac)W^=wa>qR| zMQot|119NuU=R;(*^^5}1Y*jelcj^bTl$k*S!eE)?0B&16zYd_YDG$vTk?We^L{-e%0#&Xz za}Vv>ZzA~TuMcvj?E6E#t-&Ubh3al+ez=#9Vbz&9S|ldQ=7U2YMHrY|kY&s5XA zMfBsqzNf*7>T7_*v!oe|>KlL|rFDzylLKh^j~jGcg7{Ty#`FYCqj-X(NqbHkD5o6s zL6i;mo3KJ~JT{q>{x#*C!epC+9j?FpuxqhurVMo=?7W>*alogLzplLU$Le`EsFp>| z8B)67eMgf6gU|z1VipjQ4B~ggRbATbUFv>j#k0&OsRfBe^h^9~Aki26r}ER`j1S1y zhJApCMBK!Uqhq(mOO|rqrNw3S5nBV3y?(Q%-6wp-5mB1D#rzq`A1i(zOs1$XVnSDE zWxABXe*T9VYUqG{75>H&eXS=iW+K6R0H!NR9;jmlVvWJ6EX4mSQVXfbe0^s2~s zfN?jreU_%c0jB%7BY*R>SjM!V?fD>vr># zgvP=o{SF~_WvN%D6c}@^n*g)9zt8h2<@IJhD#AN~O9~@ep#R60_puJ15B;d@(4=;; zt0?GB6=eox(cfm!4C=?uKezjAxaUDR8#{lSLI=~7+4pmQKwbyhIEjpPX2tSt!avKZ%k{nlVZNIkF{4P*@{4QW_ zmhc`uh-0Q!MWueBJ=R(XskTFG5%v1oVM5T?(z%Y?L+L8(geA*mxtstlJ0vX-@!$c% z&nX|zOM%{oVp>ro585McmCRrLRFTtlsSvu*JTd|pCtNa^vpk_x_Vku$gSGSU5Xnj> zq1DMG^d!4~(|>ECZ_fUcN{WLU{H4^qUvr((+zr<@XTyq_P946BAfmm$BjyX9_Xm6q zmdFl+YheLt8rH=Z4sJ+&sQ`(*?9o0_^O&78KF{W( zlpH%rNjNjc#}y&8F8ty%EsRBFP9U@2V`g<~(ZvJnAo4ScAlOgz#!rBHu}nknkGuJ% zzJ|N+&qSuQX7%j|5aTiDuVar<=b{Sna2I+vIfoKUyH`h78p<+p7s9FPH%M@3i!o~9 z2?$Tt9+F}RERRdFt>Ix&gC(@J@+fNVq>zK zY2nhJ!$Z?{%76LFtu+Q2lltV5t8UH47@{&fwonNh%EBoE+D$#hZ4NHYP)eT@+=@9Z zRZ5=-$UwJ7d?(%kGrLi^+r7UJ#`k6Yq?TONp7BOTNgwM~x-2-lw%WPY`o|qzifeP` zINB20K@QY^$gUs|KsoDi^Cw}o7^RF3e1Aio9bNw0%>$*|4L6Kg#%8Rm(>Izk7PeS- zDOS!GE}COa^36&Vb+{nFXpc>K5u+VEvJKoBkZvjYyy*!GnDIX5Zli-zUh$M@fS1r@ z?pM&Ify3FB6-~gfIks%h-Hpb6anZxW%wNV(FFDUj|5I!PVJ4=5IbkfR2?ZfRa8Gc* zyEn0G8v6V2csN`yLFW=vj?TVZ_oinEJ|5l$z=P~?nkO!79hE4d?rk;f)H1BCm4ko* zY!mvzjSBO1&l^r&ip51nvT4!eVW_((oL$HLKlfk8JXJXoLKWJ%s4JtM9W&3@Y<`pY zltRt&^dZeL8%Xoe=)3i{K(910CyaD)A{;W{srt!dA~v~kxxnAuvE7l)T_lHaqti8< zenK-Xj+&tA4Gnr;czOJ`1Ly6ti&d!vVE1bR?dcM1s8pU|2$dgL$i*QnJA~jiTcSL8 z2(od$zOZ+NDqK0QP@uw9GFrq=OCx;!?%qZ@G~MsNs)J+R3m&I>q?$~AXU@p)(rKoP ztoBmbLIYe)ESpU>6e1Dy*JKd?rl<2e%>T50ckJ&1#vAq( zTHeW>jz-fBh&w+Bea<3U;RJG#VWdev%#>kcoW333#NiJ=c6<2P6;6`=p8Sl{@=>9L z`V-*e#&fvaAHve)WND=;EA7bopl9ukLaJT<2%C5zBfKn8WX6&?h!5r#vU&*-N( z+tpSxRRau}1^HfJdU&`W>rHF`UE~qj7yR$LXfk`7PdcyXJZeg2aMW9LKm0sn(O}qU z{_i~1M6f48ZX;X0bcpb`Ju%@|+XY$}k=eu;!mq5FVsFt#>cuEb3W5;fJm57NNFSB;q1z=4H;fb1QRpZh+?nLHq zei1?ZCnaCj|5dz%o(V`Ss3L9cQjO4+wQFE&{heDuZHK02krYnEkPeIP5Jsh2P$Kt_ zC>ukyPU4emPQ5D4TzpyM|7^~(7sW{-VvGo2RSkReef&k;Zt#kgR+r;q`gxD)QvLds zH%Q)-zuS-g$AA+HcZkO4dtMG%H~#Z|L)uR{eE~3JQPuF!+ zD%v^XEQD#4^7;~BWodTu`agi&d z4~G;iLxIUnuo&qyWDGS~fl~b{^SU^^iS&a%hnyu{6M}5?)!h3M{SBUVgu`!j>?RGP zju_|u^W$MXfyi;Sd`=;rBW{PnfuO*s)*?vsD|V8kEsAEF z#H>7+46f6xO9DNO6a5Pej5{`<`Ltk(-h9DlxgxpkjXARLpfyQ6c9K-bj7wb#_uIjD3o!IMd)41s;pw8XkpXHZVj1xMdcx zbTVOGH;)u7sC_ ziLrNyS=hquZ(%5>I#-mnh~~lEz0Oz9x5UFP&z3|MlZX^&>I2|fjw-)~Q9^sH3|PEW z2N`s;x(=myYvSFkk43_9XJ>3%EhLwGXEHh$K$WaMoQJ?wMN&W%@3g~*MJBsxRxvET zKA-t}$_mwf%%HrEbo`k)V5Je?TXDOY5Y|#rP^D-wAM^vrQxDkQTwQ8f8_ycgsom6k z5BQ1p@or@CmL9}fCFNa8(mpZu4ylgC_ zkgF(8uQ4ZjY0i%_SyRKi^tm61O_JQTwJ;L`jgt3s(0cz8f1%;4t4zueruI*z_9Mx< z2Qg%Pm50yt49}RRiZ#uwEzjA$cIi+J#FUbv~RL)Dn`$v@bFK@sqK)X#3P;GKj2g zthKFd|Pf33H*Z&rC+eb!qOuGG=YXGxDyGY{B!~rY*UX-;>PnJ&6mo#lr zRbQT9_aei#QR|m)J_oFBt&|FI>mU^6C8_c*!=F8nCa9*L2{xU!qNeWv%l38S2oA4b zl%}MvPl>Ihl*^yiAhOG`B(dI6h+M+WE~222JD3)&u3rf7v54r6k9ninxxHk3V-B?I$16IfL+_yR_eKOa?AVkOI^BRYU!m zwaI(5AdCi>COwuhulnx@9Z4>Gr(IiK;vhI}|Bg%em>M&Mz}a{`oR`fStxiVn&dCZV zNw>jU>~g_mKn>mVxObMNb7r@O0E+5-?b1;hi;x%UuXAfs0)oNC%AqycsxO&Ez|JA0`elzneJEI#dsJEek9(?h+a7zu+@PH$Ap`YC*LLD`bcs70xq&xO?p!EBFl z5Vvdh;aHz~&v$#d?xg&~OkUF{^mm~U>)b&qo-0$8% z{C8gOA8>zV&%UEA{T7s0rHg3d3(Bg#$77ZC!A*itzJp=-n$DNrg({pYP|!e*kU(LV z;(qbf>qaM3!ze2GxrQ+x?8xFOVdpBb(|L3lN+!la=Hiq>YnTv+j(rU6U&9kV<1i<&lV#WPze9xEs>uIWD{`ws!5>u!^CY7+UTGQsaesK6AAK7kK zMIiQOPL(8UZYK+7x4x;k&6C&Yd%RF>Q|*{yi>DgsIfX|&#k|=YdWp4U(Ez`Zz%vVV z;`A#A2ke0O2VI07Lih{uJ&DUbIzXTpRuHNGQNRf;FBfWtBI}|p+&ZcpuJ`LJ5^o|* zYQCzBS-|yT{2ZL6Jh^diC4K7J>Y6z=Tuql>2w2|S(9HWn-2CjIEJqBy)D09TLBDx2 zJIXgp>=QCyQw$rw>>@IxkFwR90$_PkmOVpRt(XFvYc<*H1JV8mWrolESGQ%%Te{%rvxZn^`-;^O$M=$_;eFk{x{fvRFI6TrWbQ(4%0u+~&}g!AlHvOP5IWB*=2(xgX z!ITVUzo^h%7VkvP7p~=_AkD9)P+)TMTo($^8p(DPD3)>8gw*!Ta(Pv za&l~Ca%|<)*vjd#+R3rnU{4J!Mcis_u$GkOO zc?-DcJNSkrS2Z|LDL0psv9583+*VvxDE1<*Yi^u|Ew&m*@2JfEAttMhGx$7lvAxWh z>135YZJi$HcoQv;k4qm)63r4psa*5eY&9vmcPVYW66w>oM6w>-)%cc%|05A#Y`X`A zJinormtR~%0jrnWUtFO9m6v^BTp$!{6kQc_Kx-e!+4g5~YG!25&(DaLv0z*r0SlMT zU|c>3yrcdfRqiMtw-jMqSX2dyq9|MTmvOaRRey$$Gw;25^PBhHyx~8DV}E)0y$-*x zcSS)ULRlbUS)>vb_r-E1dCF8I(mA1=wS}@mGDId>qL3U>NuFqRwVWdbGV)X?t7McE z;h85dk#Tb7saV#CPA14%pbC3BnIu!rNO^=7%A+)2E>ihmjE-!NAHobD3GO9Xpl2Ey z`+uD%;6K%XODz{a5nSnGVQ(Cyr=5}JM0r9Kfcx!)`?J*w(4WHgE&+JXmBAwY6>G^$u z&fG+aDO~3Bg6}{<^wnOz-^xL}SHJhHR+ipNv)wHM{czV-xJ38{})wXK|w&(hbn- zIoE8`1)Z3I`C4Umc0s>#rLkkOnm-S^7!BIY^>tGR&RE>5Y*Q=H?PklNP3i`=TYuAo zI@R>=`K#GasQbJHuY!qoV4IG;muTVR->a(ar|hxPitU=L!mhJz{)|7Px(mI^Z_v~sGDvwM~ct<4NYs3(%k%l?$^!b<8B{&i)GO_Pqh?mTC-I7FZIhYcCX{I4 zBXrmHgGF86q%`L1D>nv=+>W7uYX$rF&Nu2 zeIHZ;J0d-gyZ7D)_ipHKRnc^P2d0cIAr57$D>`hZ#VjD6_hjVh#GBi<#&$K7+#AFO zXunhUJlJdw%X2F99owf)2N&-((G3BhhU@LP;7E>R`<#WE4VQw!5IONqr+Wfh1qvJo zm*hL%4nhw`R_ve;K1SP{gMaw(<0)d_Yto?Z5&wn;5!Y^k8`C-T<@p=>&-q(FGScAN z0VH{6r2}ZgQe)rO-={4K{NVkj+x8RFp@=NRfsTF-aG}INFGP<8id>Up z<5gk*oRjMK&ahe=(*UdwtS5Gj`oSDnj(_j-?7`XM0n{`wd$9S~mwzmLK0)K;Y!J0o zlj$aAqgX+V2A{Z2cZcSFU^i&r7I15ewt`_ZY(L3t=+3AQQU$DsPHYlt*-g_y?REl$<+VB~41FL>-mTABj_1<(6pW#bUDQ9Q+x_5Z z$LO52idL((WdrCiKY!%nBvYLD)~#E3 zjCd^2lS8cE-PB)8`xbfL9gHj{j#9aNY`V**GI1+UG2%Jy)PGfYS7ml|tn-P$!vTf5eEc*h@&X>%EPV7$5nzv|X5y*`^{W^fcjUD(2*)uu~I&W;mH z_;zC#ha8-%n>DYlu3oEHS4-x4)hb=RYAvl+ODn`Gm6j~BMwjXOwWXEiinV@yt+c*g zA=j?c>r2aY1%K@86{8HG8p(K;MM`W<{4A~UC*(H%gv1u*k`pW?{76ktuap8QH9fr& z3MKRX(<>!`vnNLxNcPdxsi#XcdD_tu6sBMYHOGB>f6ZvvM)16*0)s&g*6D~IxSmUAhbD|b_HzX2WWE8? zbaP>Ddw&$h&H_hny9m@Ia8-b7s-ZyDxyJd%x@xFykHhFR@TuEpfI7#i37}>;brz`e zAp0Yby})I+hGZvU^dje*0_xJuq#6#Ud2JgESHs5t24N_lW6Dc494$5-at@L|JYwX3e zhrNVNE)`+uB1}zL(SPv?9?dSNBkbjrF}AMIceuXS#k#m-4*YcN`PaVN###ox+oz7E z+pgbkVQz#ofS(XSr$zPNOmxvODs9_=y4x74aSh9~>NLvKXb@!$jOzqC0|K4n66K6I zz<=Y#=lWf+(s*(CxGRqG!HQyitKS`VQQ<9~$?q}du}J&SblQ~Dy?i8N$roi~3kyR= zvnwe6V{8_%c?FwAY<>bwPhe{Zg_dT`Rwp`d7_h?A0C*1rdjow$ltoQcp_QRk#cAG7 z@^<3bQxiuxug3pVx+so|iiAC~#MX~z5`QVlCOnfogeHVs0#P>}fM@TEo5J3OKngNM zV_4R*msAa1+6i zp2z|2Wn$oD)DS7Lp~o>)4WrdDz<=W3;LXYQqAE0jG+D&@xlxw$ZB>R{ZK4s+0T&m0yG=2Q`4tKD&lRS>@>&v(|;nyBN1*3 z9|DSxr5LqmTd0Ch+>;_{aVZjakK2;JS)(r9ZLwQ_Ky{c=Wtf3|0>m@W_5V)2)}NYv zcoG7x{*S{GTG^p#Fb6AXF4`00XbZ%B$)58Mwo=`2YuNC z4bJ>RFmfm!ijW1B!f%65MW`h*L}>`@&p|QFpzWbdat)RJ4Qib+tgiUz zKVeknb%NT>6Q!#K%$OUhp%iKd6Zoz1P{O*RJAV?4ADjtC@Vz@4 zoW;3j1pL1D>7{NF_(zZ@91RP|voCE3-O(?^$5%s*DA$Cp7Usjzg9)hB#!v(FX(t8l^d>v;8QB}V)FV@9(Lp`3gNOI0B++*oS^*2Vr*$6&46MwMmu9)^3IGxeFJUl<2LgCZCY1P74l{982!H+{1C=?D4%0WF@XXlg zWg;0b&yf<}>>?$;4fV2cmGNs))^=UWqAWl`Sy{HNR;Mg`&>oNDOp8_jf`({39jnQS ze>5|6!&tltYcd`G)*>)J6M2N*!#L-4RHkCrdXtf6L*DcQ)3u=Ng5xsEe*hI)T>oTw z3XJmjFc~vDk$={tO^yxEBJX1!6 zc;y`OC}X=pq*a;MG~zkcz)PqsNY!X>telUNC>CLAx`k!gH=UrY*#KAUVC5`npg9dR z$KmGit;K0r6W+@*0go=rj_0-5FZp@cV)RK_X3!mp_J8rzg=z0ki1ZtXbPj4OsR%U| z{5a|(oSuYQYg{VkRbG!N*h*NrDL5vLz^E!sVEra>eLWGbr55Y7f}@u#k5KNLygdG) zukV1*yIuf&ZI>*eJYg87vtxFAqhDpiCenaSqUBQpFNA@` zF$^|`U4Mgf3v(?$*W=Tte~gv2xQIe)qHNm*Orxo^qG}QYKWp(#@Yzxd58J`!GicDX< zv1LX455jtf$HH8P$HHBQ$HHER$HHH?$HHKL7X}>yZxgsdw@lh#BLV@Iw{YBGbO8dF z47cXpU>b{m$X>u$W*20-Ny}@x;;`Ot^f91ku>l2j?}`=Y9!UcZwi$#kSr=er<{ z?K4+q1J9KqgbJo4a7T%iY9=O{a~+^2ItDv1M^dGKNm|YI4@rw1Q;FDQm-Y#F+3t3~ z)PMlCEE7SNqfHOtLT&G#X*M41epb4sRvPiQ7G^e_l;bpsQDLzZJLpN@9kxu1cAEMH z6p3fxFX+5B)czLzcFhPaY!JAROtZz|DRTFn5nYiX)EPX-=e3xtchBe^n$dlMAq9|t z)a<~2!ko$^Ej6o|o>_fP&FXr*RY(2SUFWcS?&6tvr*jC0<1M0u9zyDptl1P!r4n7g z&t#tU=X9CEv*{#xf2j}Q&v*dtjhJj@B=Ff!B_(jKFgOG;3QkMYEZ(etw{%7=n1O|y zKK8ZQJNRR5q+wyd4O&m6ZRxuF{(<#ngI*GUF~>&YEP=8YN9HPNC(1~fTWM5TjD!%7 zutyhwP5UJv=^%-MIjszyxD{X`QeliU&7#y?YPaL42+?e~G^tbW6ilF#2*#b)j#XVLpe?vO%Dl=7T}aWEbwk4}5XXCQRXqK}EHu2k+K;wJ(QSV6j!`G_M?aLmKwe z;7_<8AnwM7Tqhlu3;41ze>H^TwD55gQ&^wDHkTG+wnT<8LPq-jObnF|!`PB!%&4AD zDj>66gJvVz+BVv-8(Vr~zF??GT=!~!lJQV2C{D~Jv8ly4^;l+V$-MK~N_8>1!1+ya zQ_5P=>2Lo{a6CDS9^BQW@h5Z0E0p(5X9=SP68hE=mBhk9??iC6!t*)i+Sg z_S5}_2e)!V25rWX(byyV25ERHGHfUzhj;Ivj{1&|@|Cgge|Gr>M^i>o7=1SR4>R26 zPsjEKk{=ZT<{RI@z@F+iuz9b4xw70lu=$$k9ad=0d&~UMf_aZBBx9S$*yg>CvHf;G zCc|(0#Xe)>8=>xT)IrrwjSJ5!rll5uusu_Q*i}mR+H@gCVt1poqd~l`O zg!B;FE`sNL{)7sVv>uxon))>>4vbRn&9~K3=ux*ZlX)!_uLEc@E7m`|UE1sm7o$@e7hfHhPbxGfj>wrPzV%kkILxcq(X;nFq4MQ87-9}x*Ix!+;%&OOh?K^ z%Or`_B&dYTROwOldv4UgN zl5}S#KL6EBB#O6x%)4S;UV;w2{nv?QBd>f3W6>f^YISaR(y{r2*F(cwhW89U$16=7 zNVeCp(c`$K1=eETdn(%Kv0=-w)F889(_i*E{yYGZJm}0hE5rVCNDWvgF*3;9$>YOX zdKAifA%@@yS|@>Rmm(HJ^IrBtkI^7k2nyjQr z-mQZ_7DJ*eJk}&aq~XzHv0aN+Ph@GxGq4-;AXr@>Lf!qD$kvdNYh{$bQ>H*AKVvgk z{~YWeOHuaezMx2(wK>&1rXCUN8^z#VZ+}$8ca0~+=XgHz7D|Y%dmo_ z=ABj8M4M9{G&v5%AUe{;Q+J9>75Uwt$kIsbC$h#)QPZh>D<&v$JJ2G%WrCtB67%hU z-Mo^M#ls}69qve$Nl;Uf@^eX8PpaQiZZP0 zjl1W2<~uSLF4rqncW^MnLxU!q<1F}pg9DOa|K)CbZft~!XxF`sZl)PXX{hN5xkGD` z4>h6aAwPF0av*yM74_NJ1+$}k*`_R@nF@a3PxCeUSncwvrE<`$bWuL38YTC?QK9L} zFQ!*YY!6T4ccpk0TaNXCW8^l;cY`qPLy1!^m%1k>X_i_$EMIvz2`Uk;zg$y)GlIQ- zYt@duRN@z~DL&d4l+!_`c#ZNbCT8J|*_1Dvm%`PZUBD64WDoJvv1ZwK#yl*z~ z_^MvtHG&%p@htNiQ7a^x;(;bNxI=FjWUvIwdDALH;u&3A)kzK6P$3k_>_t>Dsxdutk;eRLtgZ4FSU#Il2oCib zI=+%{I}^neTG1CJ415*Eh~;1Ts=-j;?M zPwkZW?oA-kDFLS;vSE9WRHbD*OFB4zF0>Oo-V1$n0jQ6k%EaDl2)PV@7ZY$%P?4YS z_?AND+TEbyx%2#STvj6{IIfpdhTt2EooW$DNpIzxelYC^W0;OcF!jz^J?PdCo?(`N zg{FQWhH0h?riBQmJ)txlcpm}vx)#MId7~1r{y5u^RNC{ZetQI)QLJOj2_yA+k>@%A zDBYNHTZ)#kXnG}?*u__Wv)G749cAE!Sd`%Ywv^)TRu?-HuNdAks(Goo(ojC>1aKEO z9Qjca{yYhIgEUvfUKinBXHfD2B|6uK9wrArt1r>ZSNRbBQ$(8sz(1W2Lfwb1guo;Zz-&%?gp#r)6-|W;4}Vp z(*L>Ue;Npw6#bun+eF~{zW|XVccnmt=5EjhldbOI6aN3^#8l>l6B1a#2hhu9<6>PR$35Hz&<7KFp3)}R#Cix;Mse@F2(6hlDCPefh=X%=6LZKSQ(l*IOh4_Hc1N{KKp;~Jb$ z%tXBgjsg_7QG5rAPj#Yw!gh;P=x}!}XmQ?gLHk-huQH6yyp=>wuv2ix z^5aex|JVfkc7Djo=Ce*NpU>~eZ*v?v8b;}Cakk`tbIvIJjyhYN`}mjtRkg1F(9W}( z*8NrAD07q3VIKtk`QPju<9kSiRe7vEUtdiSs2^z2-QBi|C4d*PXV6A8=*hl=9`uno z0!E&b+S=E?xp~3&3W|4@k90T*vYKE6Ln;J1j$V^}@;)-i^o?~iVJEpsTT^+AeFC`d zu~Qs>9rg8h3hVljL7n2Z-&v;~?U4Sz{(gZLOr`oYp6*xFJp8u<@i`$|)j^a42>76_ z0;GW67Cwh)ZXB0eQRLVt)oj*%@1LR_BXZn(XL0mXIC@dzbjE74jsSMJ70Z>`s)zOB z9Yg`H>LC{0gWl;OT+PGlLPzGeH9fgu1Cv^RHZZW_!D=zf0W5B_6bZT#7FN7^y*4|= z-|FzTjtV|G zj2b%e_wftF0xy26elg=4Ya9o9d zj_1zT2mw6aYe0T=16ArDLd;77wGAcT_g7B=;#BZlcRg6 z#>cgwV2JP46Rbz7ha{=nA0!#>et zi+em-w`mE!6mmQ!&4-=OPR5?DVA#`b~tJkx_?Tv5;<-aQ2X}T*aU2`?8AdlIvkEe z@KBhcF@4XjTZgzIw1(^0$xza8kZ{GB9@!O(#k@yN>;y6yt#O(p@m>czhL z1_A!H6Rk%krAHn{E20y3#|ujhwjw0uj)v5Tsp++Gsd(FvYG8~BVpuBMSOml>C*Je! zRezJiL!f(0e!V1v;_wI!p$3E$k}@SkZjo9spj#;_OYDOb?<5ij{KRJIL2qgDM8c5m zuaP!{v`(qm2ok#p!dP$xc~o#0ay)f>>iF5ir%Gp@J$vT#x#OkDQ-_}_9XUCD&O3${ zem)|G**b1tXgfx9RZK}lx<>D3%#Z_hZhyFQGE`f7P7Y6yn&VxyGkk(7GRRdLrD${# zbC}5xP%Xa#G6X&XTEDa;m0Nh)(k#w`IxZASLCA!ynw%5_QV=d>Z(D}+t5ZTL15ffs z&T#mLtE|DBq+oBh+g2(Y8!}Vh{(nRT zx|8MGM5}8-mUy zn0adTx0=S{Ta;=EXBbKqi=)kEz0bh_bp^(*eabAfccp)oh|SUf5uJl7R#!%Dn?}!u zoBGNos8OPH1DmHcb-B&%uIyCnM1K+?&^luyGDak^HkJY1Bmo&$nhT--LIa&x9DhSb zREyB&I|o!_<0O?i45tSBf^{*~<|-bckM@XaVFOe(6Vhaq-EcVaD*)LoO?z4Yzy9s7 zVfK<<-p`|9_$fn0TdgI}1ApsB0DA#L7J>aXTRLeDRe^MFsalnsPvNBB2=~X8gb9a5 zY=n>=R)r1NM=g1T>#En2_0faHdZST69Ie7jvWYvHG$OLF9B;^zBr8L5vhczB5@?@f zeab4WP*%7JUlb!S+4`4Y0l72bZBL^Pn~cD|;QF&yg*40PD}`I{%70dc0xetKdJpLv z2rkm9+&MdR39=!W&l<6CK;>u~Y7BEEXgv`Rb-y$NfZH(NZ-c87EbwXQqaB}`#xd>1 zLEbeSI$Ir6K-Vtsl`a>pzlml6jhSqJ!v=eVGsGx>z>BcWW74ONWne=3m*CvjDP%!EmATaDKhXb!ko9> zcUJBnT$m|ChFj*f=rvRz3T*OJpq5suyxQx&nh}d-&u>h$(vKfF*xdHy{ej-yIHaK| z(MwZ%u^+Eo(FC#0&k^N(*^tvN&?m5!gzbTYTwF7}^B98LUAi}O;DQVP1@GYZ*-8=u ztySxx2t+o@HGkrseKQ=;yyHA-?bk$%vonM>sbms6$uE5p|uI6cMN zQ-yosK8l(57*9qlENuUr;(CI#dP8TQjdbsm%Xa7{W`9cehhcWP95#mam>=n0v<(~q zZ~?WlXz7%mkW~(c5w=(l$5FTtuOCsUXd2_n@s2dD6?NVIY$emQWNfZw#IVA%EFXL3 z%r`WdcO}O{A4ETPsGeR`LpZ%2}sf7uzSo@G^&4eJCsjoJ~R@fQhL6&JOUcBC@&@@j%yyQ-H(i;GLzmLmA z*eKq2jg2f|3e{D$3L6KGUEKu!paFedTS&jd@_(T9JXon+DOW3^gtwI#Ty(6LA5N?n zqV-$%NAs>7rFL1rE&T;zvKbDiOx_-ySwrRk!R<*c(=TfwRA(&wZ*a9AR}bqPoNUP> z3>4VZHfZD7urj-D;iWoeTgXez?KZ6qeBsR*J~ag3%h?pp!Qaj`mX+c3lRCS+Kov z=yj_GYZ**o;z>f!0D~Z#rpDubDl*El8-FM0j>Wh>^HDN({CuYIlY-Ef&+cfRs z-lE7Xo3*V?Yz&!Su)LQ=mhSU(-^ceK7d;&Q<|qArT35MI82|`trMLCSQC2{*@Bmt* zM#x@-VVsrVuS3`;ZH-%l$Ce1vLd?Qc!sCS=oOXq0g|WCF~Q)hIZo0-=I7{ ziz&RDK}?P}NX^C)1U8zqB7@zm+>qnS@hVUDJT||XM~EA3zF#r>+R6Yi`>7HkmHCW6M2PCE&6K6h4}U8`0#N8C ziEua;2KGq@+DNJR7TWw~DtX5NS=XKP-Yvq3JWyrrTB$!qDzyXtUBn+`2nFrtaISYX zQzE-+d}5do($El`6I16HZEudV_|+lclx?cDQp zqV?#y^+6Z!W{Di^5Kkn_NPp?X22tK6Bxj!+w9^Wi+?mPcT;B(MUGv_ z$BaAlR&TgC<=RXx%XD&Cep_QI(Eyd`5#=N!a&VMKT9QOLUV}6aTN2aHTGc=Y3XTaV ztTzodLAJ3xn@XifOCT#!^c0ldA}thNg0zf!gu~0I=Wm7?=o}He2@G&W;i>bt&tbe{K)xDBhy3CMA@9wle zqh=&FBvx92dP48jVbI5F1!-bM93anVHm5p_$qWMZmZtr~Vcr(aLJ}x(ZCKKfV92~wwB9FhwMW;wYZkbnUyN{R3@aFoGO}bCAi_nrmX_k7{?6`{ zMv3hU*xPHZXMch@_yv~qUt#?|&dV#StUZTs%XrIqwNG%gq7y6IHspRYu>Ooq%fd=G zw%TlSHIee7eMdthux$*K$9HXuHj%0oX3I+AyVQ`nsS9;~V#?dLk=0?kR1$8rRJt=A zn@L8ZF!gL5a}qg8Hnk{b8iGjbGNPUbiy21tH;yP{b$=U?W#?0Tv_G*;2BGlY&j^zv zcS!WPk`1Gb#p_r)V+dVEt23p1{=DoCt93dl>pv{;$+p=dhu#2$^P$6TZ*Ye#OufF#UH z^hG848Gqg#U0h|LthzfLZii%oMIlsU8NAIU5R41~6{D2(QP?0;+8hr4E2gGwiQh6_ zJQi(QYsf9H$24Icgq+mEF7*esBe=FV)0yL@r76|n=b6NFMkse6k97flFZ#UUn+sOM zgBk}{-lvG(;&e%k@im9kCYHsfU%HmVQ$h=rzJCnH$L4ZhQF(2Z*Qp_gz3k92y_^y7 zQ%SLC!D(g)Eg8!hKSL;v(2P%r4N|{RFkJcYZjO-EPZ}TBnwe3J^5&?#WSo+}6>?vMDRO?=f@vxknG zn}1-;dJ!Xz&Uav20BTb&v2s1^!Gk<^@}`aY{1*D%)pS;em;0XAYE`)%L7dy{+(mmGE|8>mxqM5Jlq`c$A1?r`i_r@{^em}T!%2mbpNAbfbR3nL3RIG zF-W7M3*7@^S{psPWF@g1bAA-)>ovU~l9lJ)cV?YpV3W|l`)O@E__ z9-(LI?qM-XGspCNezITrFmGRZPvm?!rou_G_Y3>MuvCd%YT_Ln*&~Lxal{VTD#)34 z7$`u0Ms5``5BRbb7=G+%r-zPm`Du-;f5O(o_fWB0T>W-Nx|-tH*B(h&X~%3V6YwV@ znj9V}-ZT#F+x2>X5us<^DvqOMet$~~srbLdf&Ea}ErqwJKZK7sf&+W0u!9P73T&$w zxts)p$J|Bw0#=7TFU=gKQTfkD6vnS;EL!qmgdm}Eyk8766^O1U`FC*S9wgb)DQFRg z%QztDpZAY(^N9?GN09!&q?NM8Mf83)5@)e2(~P{h}zuV zSoWdzxV#O=Wz@lL&fy>K{=u?x2JeC?)4pp-w`d&-r$j!@;U~<#>8;J}vXlhM-Z)bC z{+P(JAXRxq#`hu|s{+nK+Oii?7CP#Pxv3yS7-*K`8Cq<16XXv!8h_XyyIzwv-|TG5 zA&|O}3?M#!A{|9f%;1af&OB zptu#cJ8}49ZVj$jRXBsgA`UljV3G5iYzJVd1y0M=^|95;ODM_oKkNa#0Echj@P2$M zi<%+Rl`;Tc)(5bd4}V)>Z=A5y=Xc!@3L%R=4_|ozEt)7J786s_x;aY0WhMN3gkCcQYrBLAb-y$urX^{e)BI?cMI!G~%XVCj zh?R?cM zZN(tH!6usYE@wHzd4H4gf{ZgHx7Bpu+D!yZkFN~FZ-0Ui&aU(-cmM1$?ZvMUfvQ^8 z?4g$B_%2V^x*}5LSLC>*XJxxpi5$L#)4v3Jt7eV^)aTxW0mQePdC|LIc;AK@wf7O~ z(cDew^FG2Y{Wi5U-^|IrqrCX4T=%b{(x31CU6;RI`#F{4*Cki-uH^%FZ!j_ zjB3?4tn~|2>%jV2G4FN_ejNb?4-4r*CRa4ekhei622seiq_x?4lkAgog)nCrsf=Mk z!W5~{a8ZsciOEBP8?pSE-W`@}EX{V;TcdYtxQ$T^ zx5XttYVJC>&_dxbo5Y9T#X+m8SIgHMDv4^Jjpc&V2)(6*J~GN#{nDb6O~eJ{>*Df- z%70w!LeL(LObs!$pL$@9DAV!qi+7t-4X`!;Xn2hoz^~TCIv;oUyl?Ap$aSNwfJt6p}k87oNH1_Ohv<9djAyo;d zS)~>jW$8(E>mP34z8%;y1DvDcx>_cxxPMFSUDEx1tvglKiPaNFI+&2UL+RMSUBd+4 z;`Q-ea;_jm6Q^&ZS8Z$cBr01Qkos~qfI>(D*#qBTjsUl;A3w?TO{Kw>#Jy^Jalr~8 zreL7Mh7Ep@R`WWrr6Ez^ur&*@403yCY80C=E1&wn35PmxX37m&;Z2M8q$nkt_d3B%F`%Q;qi6Uo~g<3huV5sMV#-NhR zj>%o_24X@$^-G&kSg#fbtA2ZozJFij+4jW{=BpWO!6Gc)_=WH_ol_un=3ypg!}5f2 zyS#V!J{{d>_}+OPA$oMiD=+vKLia+&=)LY+go)^C-r*|?R|_fcb!b!w) zDjb%O$6lBF7l=B@HdD))+Gka6q9eRN;XLVex&Ne@R=KaJ+z#XH5zggw=6}bNrlU%L z60&Ye%%7Rh&i9C{3JFIosEw&Khtp2rJw&;LWu2x)-;|}RPjYX_l3vvI132;%S^jk{ ze;=o0IOWr*t2QipR&q!s>a54_ZL(HLeMy$T zio@3s5&n3Wop)kq*9py`lkdiY*k80Sn z$VhAtk^Fn4OIh^#@%7JuOLi;QvxG@!_wD{5sbOawzz0EWOO>eC*MFfU7-PS04fM*5 zVU9$A0DiQp-egsHZNCL?c=*P@q-)D2a{1W*H3cf`dF_MRPgzio3wrhu^L*%12kUBE zGQL6PXxJCiYX(88I*0D`u2|R=!Va>F*GmdCfIkUw)>mRGxcnwJ_Eh>d0r z1XXxH4IpVkI@IZI6n|E0J5gMCN0+gThdDCUnBLlzU_+9?JT|#?8`$ zoML(8_7zdA9_cZ>O&Ng|IR2P)Aq-ihosSp3?;dY?O_!grY{gq0^aYv9CHQgCNCy@h zR1M5x^Rp6gT}fI|V=YLX@0W7xGE7`bDqS%k% zux5q3H&>}!)@T7d5lRq z-{a^q9t+2D(MN6@CNK`2EsOC>c$KFs3s)xZm&$vlvIxtR!Yxb2vt!-7BXh(4OJS+j z=mulGW=PI+{eS+{EFFnuB0!wn`mW*#F!rBKE7NCe=)p3p+gUq%cAaW5@>m$uBv0#O z4eGEjW6uQh>#)JgCP5Pe97*m~-Ak+n z0Eb=BIe)?%jYXV)-AKzKT}Hg^9i2nIXO3U=z27(UPV+C$)-eI#sq$xRR~~hhG=62c zXDHH`H%#kTzQ0NX?K+{Dsz1jNhEq2VB$8OYh)aQCHaLDpksG6E5rjhFP(+t1wIy&M zaCoL$V!nN^Ogx%kJWu>F=!Lo`6r0U+;q>@JyMGGRdVOJOQ6hQzz+YhqtC%7%c7cga zh;pS8EN7^mMyUi;tKJu6<2S9};W6|{nRP!JP5YGh2i807PXnb~=glhH%*SbF{s!<0rfTR0@{umVRA4*)mXmY*!|b)&*NRcH?5%;i&4t zl-#Z3KU$%p;?ro=Us!Proj=2)j{Pu@^GCuCg>I#_sjZP4#wd#vLpe?EyAE%|n}5+} zLBAh0qkHsQ>2mD)|9!OP^wvmw_k>y2?WP*pCGFNiyCmuR#v2RkO=BTl-->`@3pRGK z^Tx4Dx7^sPb**!wUS@R=j@4~2@+c=|a}o1HYpvaewJl>|JPHXExl1)@$zI&m;c9^Z zy;kg6#?IP2Dm|EV8LF^!34Z$Ppnnv#u3o+3Vyb*Pg3&2SH@3#w`Yn-l)|CS5N`Dz{6>?|Z zHBRe@XCu7QN7*;+u%BK zAA4L235iwx6T@s>Vs?wNk3Sv@ zjZb~%8=rca{ujy<{xv_5{wb9{)3!ZHoPV}0e|wqrJH*7#TrL-J9UL|0i9)45 zp<)S-?~0z?m`m(+gp9mvQD{qu}W`ECYm+Z3}XBT_iE(P57 z0ueHLqOh|(Gb`K)8jzjxThFjmllN(9gf_8KUnKo5D}KYR&c&N4F;Ngz4vhoVib}?B z%&EPZCY2Mt=R!Am#f9A(v%1lafJ)JJg(wG*p=!b$i`7$pxOL#Tq~;R_yUL=To3-ol zxG6LUGt?BcXnz9b2}UP|tQ>vpc%loa*W~cT8D}=iI73{me4CUNt8L8^Etr{zC?;ZH zW%_)bxDcN8qH={+gX)92mnb(&&7LXjp%LV^#OWJ1WwxW$vx!%$S`?oc6N24kz`f4s(-q=Q{Cz5>B(fW?(CQuMVH8! z42rn2B+*RLYnq+>knTZeStxr`$xP>`ldbMJJ7d}r=4A!5v$CLqC=)^40pCqsc|26@ z`<@y5PC`gRLY8cyY}tyW5LvRu7)N6_*$v8&y)2Ji*>_`KvU^Ke-za<5Boa!Nh<=CO z`hDl0XU=n7_x;?@b=~KD<}+tLb4a;ae=#zt==zO?`h4?#ys47OVWv2JaeJ!hz(ysd z#Sk}8x@Wna;lBDqf+*zF9?(oR>riO!>7W$zR=D$aJ^r;*0{wA$c|FRrTX{tQ+Pv`I zHhQfWPm-;iomR7Z5Q%kdna(&yIe=0$S7xnM_ScxZC+f2kUvQA;lW6x~`lfNkTPk(C z(PZ83oykPSP>E!2M1`A!sACe-z^p-IW;lsdMeGIjt5d6K?e+BArEj`i0*OI#Us(tw zkCpXU7xCF0-%#npMI&1|)FMGIHc!}QGXGnFE%A(9C?c9aV^}cF;)uERuk|IvfCub7 zo*_y8J=MRs)hK!L5NCJcXVLH3&hAp$^bHQ*NnZB;{^&k+Q|Pd2v zm27O3%&5U+ELAOoL~nJTzQixBb9rdYUcO=cyrjuKR9SolGtVJW9rFxLet+=#mY3DM z$`o#w!n^ujEN+v$!l){sdC7UIaE*+6;H7%`_e3NeTiaWYE&9nIxs-mfWd9^SRhdYcwM{)sD7tUF-x*yDjFoZMN~xCg7=t1i&vx_6W*#_uR@xPH2JgFpP# zLe}SAW%e?+cqw;2XWGvd!wZ);dAjL(Cf=z_c$?EAIwy<`92M+tj}+FVJ|5H`eB2c9 z4<+vA&^OYgrF$tQ8=d)v7;gwV4zs?|V~dU4-eP_qM5Nl-#~TK9V71pX>dFj0!H z%qZl|mcS~Kf4xy0wWd5Gn?x<{Cr*>NW#W$|+j^8zB>3SGbJXrDb+fgHttVx27`ObD z^eU(DN%5T-7KCsUxw11UH|2A)v5sE@RnLDnaD6HHsDDN*jDpq=S%bS$Xv(PWlx^w7 z|1D4riBF3F^}%KN1iBArQ!dnbF5dN(jk9{H*yWTOQkAsRKlC8+QdvXBEfed=-I|tN zJJL$~j|rW_4VzuOx_ilI$!!kzjF zt>R~NYkA2_Ys}3x8ghbkE3(hodcDqBK|56#_K_`1xAZicuIDR$Bb#Qd#6(Mi+6eCC z^WwGkILZF1U-q11B=T*v6;ReCmF0g3<`G<>qR^<7$!bn;*dcJOS43(Z4ul`a-F*GF6|k= z#;Lti->csFws!5$SCxp;YYnN&!(WRsuHmQZM7xDKuj^Z!zhx22YT+DH8!o?iDn=!s zHeI>D6_TBfKS4jhXK}h69nPNrE9A@Z=aGK$^^^UrPF$Git1%l4w?vqpr~kX~GQb0E zn5xk_NP7PIO4bNR`*(|Gi9nV%gOn#h4;xkkV`GW^XZwo2uRt65To|A7xa5qNlGCs8 z{YA2i@;8lEPfjkp$c%yiS2LpR4x+!I)>K`Q@Yok~Z!NZRblEmPKOu@uqGR=;fOOy5 zB8DN_H1z6hb ztUJpJ=DB49BH@~?{R!yfAJt&IDN`9T|bwX`(CU@8RZi7!MAwSvBo-?e7SNqh*F;3N~?q79M z6_&*Uk+i7_qfJpFt?}+&sly*W-Zn7S{Z{?ii#A(3erj6Tf$QDY*6NR!+y!`f1-VO+ z-vS+|CI!1pc2woXJqgJh+cjQsE3J6H%ec{8c4oA#okn5jgHCnNX7pC3NN`$@s=|Pc z>A}hN&rr>~r+HABz89U)^uk72c%1pDq^V^ivO&_@j24sBP7f8Mqth1G6E$-Ogx)injx$4Tfa25`e za}FmJ`v`PNg+GlZ{pqBz)x8bjO2gBP`>$BBkuN8U>C4TCIA94XU^PfFUqG(&%a^RH>hdKT1_lCzN{wZs@MHyNqfCyOJArl@KtKD;+t7sJcpj@ zI?A-8FtIyk>9T;&>WkXU|IAKvy+~S^rf)ZN1Q9GzSeA+Raj|O<}&wb&T7XLH%llp zFuPM$QowIh_unrgpox7WB?)eA*6ZS^7PtJ|!7L@qvVZ)b`p zmL-6uT}??rl@Zx(*KrU%qezOCO5aDW@meu|AV!MZQ?M6Ld}j6L*(YHJ%70lY1C=jD{!8S6K}D*%^h-f5+ZR!ArJ`2y#a|>%7Whsp~h)#oSp0-jEl9K zJKF6Jfu#{nF{*Y%poR$^XfF>eboUSZWgmt;IFDdb8)p~qKY%qm3IR3H9RVaZ?)U$j zSB5wQV8Dg-2%xdG_OQ0WTD!ZW-TwrJE5i6q!6Td!#?c;-Bl-_G1{m`oHY5iS%!Bxl z65x6s#Ey&rc6pE>k`ct@L1M^g(2@t8LGFY3Jcu9J4yf|sqbeYl5Ah(gfo?v`+yUPC z5HIopNXv&#BO5^TA!QQG<-<8=0C@pC82|(dU?u|S7QmCNz@q>T$AH8`Yy{LD4i~{_ z0UU<_`vnj;@-g5lggAMs(?}7J3dK?NTR6A!ZKK3uFk0 zlje}UOKR`o;R5dyb_)UF0DTdhQ~-z-!G)Rvy&~u|hvPiVR{BqC$kxgF54#vd6hU0b zhoG@&{_g( zf(0{&gEBytLZ`W2*1_xy(jztn))|9=oG^cCwgpP1&n6!e;lU*F{RKcq&Fxlg*cF*;B_f9mH)|(bXU9K9E9JpZ+nFPX(hUtqyL%iq_>oixV73gl;0>TIheVJ( zK(-vVsTr7;!@>=LfO6Q7$KYu>tbHixEQh=AJ6J4-8%+Sv5@BD|fiw}u#()tK#>jy$ z5e|<8&klzlpo<6zA^pMEL*^yGUI8;pfI~wLC2X!iXOcN!;E4vN*x}Lsl2qserBO25gnksY^Hh zg~>txdE{a3X7@kZ4zSZ9pb6-=J|1XCm;VKefO946k^_jWgt+AL+F)w)#ouLnINwA6 zy>!{^!U&G+za)nUuq(sWa9l6gt%k2U zoIt1sx(NRxn@tTQjqC$SHINK42Mp9evPd;RQ45J8nZbox*qm)(Sqo>00)$$4bxlxM z3#UE}`fFj|uYvVic)d`-RR{Yw4m1vj1>jf*o#DOEz=(i!We&HyON(>E!YwZ)_McZr zeH8+#>L6j{D==LL=MMzr_3#eH;2Xd2qT#@#9-edsf%R~kB!RqoND4^;#_Qp_OaNsA z%!~vQ4R9r);C2H{=>&f8a00?JA)vDdL^uOOY%h|5Cog${*6hzARakyD)` zXcD&RkQAt=!9v{d6ep;A1?ivuX!y-9)aY2^FzI=DbbTThzE1n0qh90hL64UqB(b(I5}!SeHyyG>ZrHm$tcH%kXkVwQbG=K2#eGG zT?~mNLy!ie5VmZB3r57JQWkHSb7-VpT=@jezOi4iPu%*^qnn97tKFc(a8^5ayxB{t zgB$uo)DOr1= z8+PBpo=ymE%!v2=$Md}jgLtN6&oi7$q&YiS!oQrsxX0+SJTdL92zufy)K;Xk56Z#5mDCs(Vjrnu{L8yqz1&&p z!{Nbrqf*VTE6>(ucS;Kigor+rx7NQh2vphNPxqyp;5`?vU2f=qn(0bT5W23^PyDU| zh1@!8blE(NB~rJiJ*oE0=6mf=xaxm!?+yOtH*rqmZv3Z<)T}xCbA$DRjytp+cclg_`PW@Oz>1V(AtU5gdgxt%J+lrdQXZTi3QrzA(`p~-Ay#GF(wQpE$Q1&rw-JV5g4m#mW4{c zhnPq)-R)V0AHMc1nC-H7Fq;B7wJx5&`Thh5S%a?Q zZ`MZpd8yM~STob#uJ34?oB{h8>6`h_pXoWCqhym~*B*8(XRp8IQLavN^_akh_zbIhHXUejO9g4WwpOw;+9s(N`=6y5yu28dbPTf2 zy$*QolwnZIK2jDks;f^XbLGvAqP>&ScXb!b1wMH*{LAC?h05pYqGA7&InhqOx7225 Lb~fNEE&TdF6Wwk$ delta 38673 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 Hhd=)V1SUr- From 9398d52ddc20f0fe1149280fbe6dbf423a37d5a3 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 25 Sep 2024 00:05:49 +0300 Subject: [PATCH 013/406] Update package_esp32_index.template.json --- package/package_esp32_index.template.json | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 21b3635bfcc..4df82b26bee 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -101,57 +101,57 @@ "host": "i686-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", - "size": "320072134" + "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", + "size": "360076736" }, { "host": "x86_64-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", - "size": "320072134" + "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", + "size": "360076736" }, { "host": "arm64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", - "size": "320072134" + "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", + "size": "360076736" }, { "host": "x86_64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", - "size": "320072134" + "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", + "size": "360076736" }, { "host": "x86_64-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", - "size": "320072134" + "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", + "size": "360076736" }, { "host": "i686-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", - "size": "320072134" + "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", + "size": "360076736" }, { "host": "aarch64-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", - "size": "320072134" + "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", + "size": "360076736" }, { "host": "arm-linux-gnueabihf", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:fba40f59a2c1ed89bb3fb17c655ea312c9d6a9c3be102fbcb25f27e96ddc2bc6", - "size": "320072134" + "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", + "size": "360076736" } ] }, From 4bb287eaf6cb23303bf22bcab228f0e35a3680d9 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:38:21 -0300 Subject: [PATCH 014/406] fix(esp32p4): Fix compilation errors (#10371) * fix(esp32p4): Add missing touchpad definitions * fix(esp32p4): Add missing target in SPI example * fix(esp32p4): Start touch driver fix * fix(esp32p4): Skip touch examples while it is not implemented * fix(esp32p4): Add missing analog pin definitions * refactor(formatting): Fix formatting that was broken in P4 PR * fix(openthread): Add missing targets to skip * fix(esp32p4): Skip ethernet sketches * fix(esp32p4): Disable periman test while touch is not implemented * fix(esp32p4): Disable touch test while touch is not implemented * fix(esp32p4): Fix UART test * fix(esp32p4): Skip Wi-Fi test * fix(esp32): Skip unsupported example * fix(esp32p4): Fix skip files * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- cores/esp32/esp32-hal-i2c-slave.c | 772 +++++++++--------- cores/esp32/esp32-hal-spi.c | 7 +- cores/esp32/esp32-hal-touch.c | 2 +- .../examples/BLE5_multi_advertising/ci.json | 1 + .../BLE5_periodic_advertising/ci.json | 5 +- .../BLE/examples/BLE5_periodic_sync/ci.json | 3 - libraries/BLE/examples/Beacon_Scanner/ci.json | 3 - libraries/BLE/examples/Client/ci.json | 1 - libraries/BLE/examples/Notify/ci.json | 1 - libraries/BLE/examples/Server/ci.json | 6 +- .../BLE/examples/Server_multiconnect/ci.json | 4 - libraries/BLE/examples/UART/ci.json | 3 - libraries/BLE/examples/Write/ci.json | 1 - libraries/BLE/examples/iBeacon/ci.json | 1 - .../examples/DeepSleep/TouchWakeUp/ci.json | 3 +- .../ESP32/examples/Touch/TouchButton/ci.json | 1 + .../examples/Touch/TouchButtonV2/ci.json | 3 +- .../examples/Touch/TouchInterrupt/ci.json | 3 +- .../ESP32/examples/Touch/TouchRead/ci.json | 3 +- .../Ethernet/examples/ETH_LAN8720/ci.json | 1 + .../Ethernet/examples/ETH_TLK110/ci.json | 1 + .../examples/COAP/coap_switch/ci.json | 6 +- .../OpenThread/examples/SimpleCLI/ci.json | 7 +- .../OpenThread/examples/SimpleNode/ci.json | 5 +- .../ExtendedRouterNode/ci.json | 7 +- .../SPI_Multiple_Buses/SPI_Multiple_Buses.ino | 2 +- tests/validation/periman/ci.json | 3 + tests/validation/touch/ci.json | 3 +- tests/validation/uart/uart.ino | 24 +- tests/validation/wifi/ci.json | 3 +- variants/esp32p4/pins_arduino.h | 30 + 31 files changed, 471 insertions(+), 444 deletions(-) diff --git a/cores/esp32/esp32-hal-i2c-slave.c b/cores/esp32/esp32-hal-i2c-slave.c index 14da815455b..85eddcdfcf4 100644 --- a/cores/esp32/esp32-hal-i2c-slave.c +++ b/cores/esp32/esp32-hal-i2c-slave.c @@ -361,155 +361,153 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t if (!i2c->intr_handle) { uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED; -#if !defined(CONFIG_IDF_TARGET_ESP32P4) if (i2c->num == 0) { +#if !defined(CONFIG_IDF_TARGET_ESP32P4) ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); +#else + ret = esp_intr_alloc(ETS_I2C0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); +#endif #if SOC_HP_I2C_NUM > 1 } else { +#if !defined(CONFIG_IDF_TARGET_ESP32P4) ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); +#else + ret = esp_intr_alloc(ETS_I2C1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); #endif -#endif // !defined(CONFIG_IDF_TARGET_ESP32P4) -#ifdef CONFIG_IDF_TARGET_ESP32P4 - if (i2c->num == 0) { - ret = esp_intr_alloc(ETS_I2C0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); -#if SOC_I2C_NUM > 1 - } else { - ret = esp_intr_alloc(ETS_I2C1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); #endif -#endif // #ifdef CONFIG_IDF_TARGET_ESP32P4 - } - - if (ret != ESP_OK) { - log_e("install interrupt handler Failed=%d", ret); - goto fail; - } } - i2c_ll_txfifo_rst(i2c->dev); - i2c_ll_rxfifo_rst(i2c->dev); - i2c_ll_slave_enable_rx_it(i2c->dev); - i2c_ll_set_stretch(i2c->dev, 0x3FF); - i2c_ll_update(i2c->dev); - if (!perimanSetPinBus(sda, ESP32_BUS_TYPE_I2C_SLAVE_SDA, (void *)(i2c->num + 1), i2c->num, -1) - || !perimanSetPinBus(scl, ESP32_BUS_TYPE_I2C_SLAVE_SCL, (void *)(i2c->num + 1), i2c->num, -1)) { - i2cSlaveDetachBus((void *)(i2c->num + 1)); - ret = ESP_FAIL; + if (ret != ESP_OK) { + log_e("install interrupt handler Failed=%d", ret); + goto fail; } - I2C_SLAVE_MUTEX_UNLOCK(); - return ret; + } -fail: - i2c_slave_free_resources(i2c); - I2C_SLAVE_MUTEX_UNLOCK(); - return ret; + i2c_ll_txfifo_rst(i2c->dev); + i2c_ll_rxfifo_rst(i2c->dev); + i2c_ll_slave_enable_rx_it(i2c->dev); + i2c_ll_set_stretch(i2c->dev, 0x3FF); + i2c_ll_update(i2c->dev); + if (!perimanSetPinBus(sda, ESP32_BUS_TYPE_I2C_SLAVE_SDA, (void *)(i2c->num + 1), i2c->num, -1) + || !perimanSetPinBus(scl, ESP32_BUS_TYPE_I2C_SLAVE_SCL, (void *)(i2c->num + 1), i2c->num, -1)) { + i2cSlaveDetachBus((void *)(i2c->num + 1)); + ret = ESP_FAIL; } + I2C_SLAVE_MUTEX_UNLOCK(); + return ret; - esp_err_t i2cSlaveDeinit(uint8_t num) { - if (num >= SOC_HP_I2C_NUM) { - log_e("Invalid port num: %u", num); - return ESP_ERR_INVALID_ARG; - } +fail: + i2c_slave_free_resources(i2c); + I2C_SLAVE_MUTEX_UNLOCK(); + return ret; +} + +esp_err_t i2cSlaveDeinit(uint8_t num) { + if (num >= SOC_HP_I2C_NUM) { + log_e("Invalid port num: %u", num); + return ESP_ERR_INVALID_ARG; + } - i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; + i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; #if !CONFIG_DISABLE_HAL_LOCKS - if (!i2c->lock) { - log_e("Lock is not initialized! Did you call i2c_slave_init()?"); - return ESP_ERR_NO_MEM; - } + if (!i2c->lock) { + log_e("Lock is not initialized! Did you call i2c_slave_init()?"); + return ESP_ERR_NO_MEM; + } #endif - I2C_SLAVE_MUTEX_LOCK(); - int scl = i2c->scl; - int sda = i2c->sda; - i2c_slave_free_resources(i2c); - perimanClearPinBus(scl); - perimanClearPinBus(sda); - I2C_SLAVE_MUTEX_UNLOCK(); - return ESP_OK; - } - - size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { - if (num >= SOC_HP_I2C_NUM) { - log_e("Invalid port num: %u", num); - return 0; - } - uint32_t to_queue = 0, to_fifo = 0; - i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; + I2C_SLAVE_MUTEX_LOCK(); + int scl = i2c->scl; + int sda = i2c->sda; + i2c_slave_free_resources(i2c); + perimanClearPinBus(scl); + perimanClearPinBus(sda); + I2C_SLAVE_MUTEX_UNLOCK(); + return ESP_OK; +} + +size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { + if (num >= SOC_HP_I2C_NUM) { + log_e("Invalid port num: %u", num); + return 0; + } + uint32_t to_queue = 0, to_fifo = 0; + i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; #if !CONFIG_DISABLE_HAL_LOCKS - if (!i2c->lock) { - log_e("Lock is not initialized! Did you call i2c_slave_init()?"); - return ESP_ERR_NO_MEM; - } + if (!i2c->lock) { + log_e("Lock is not initialized! Did you call i2c_slave_init()?"); + return ESP_ERR_NO_MEM; + } #endif - if (!i2c->tx_queue) { - return 0; - } - I2C_SLAVE_MUTEX_LOCK(); + if (!i2c->tx_queue) { + return 0; + } + I2C_SLAVE_MUTEX_LOCK(); #if CONFIG_IDF_TARGET_ESP32 - i2c_ll_slave_disable_tx_it(i2c->dev); - uint32_t txfifo_len = 0; - i2c_ll_get_txfifo_len(i2c->dev, &txfifo_len); - if (txfifo_len < SOC_I2C_FIFO_LEN) { - i2c_ll_txfifo_rst(i2c->dev); - } + i2c_ll_slave_disable_tx_it(i2c->dev); + uint32_t txfifo_len = 0; + i2c_ll_get_txfifo_len(i2c->dev, &txfifo_len); + if (txfifo_len < SOC_I2C_FIFO_LEN) { + i2c_ll_txfifo_rst(i2c->dev); + } #endif - i2c_ll_get_txfifo_len(i2c->dev, &to_fifo); - if (to_fifo) { - if (len < to_fifo) { - to_fifo = len; + i2c_ll_get_txfifo_len(i2c->dev, &to_fifo); + if (to_fifo) { + if (len < to_fifo) { + to_fifo = len; + } + i2c_ll_write_txfifo(i2c->dev, (uint8_t *)buf, to_fifo); + buf += to_fifo; + len -= to_fifo; + //reset tx_queue + xQueueReset(i2c->tx_queue); + //write the rest of the bytes to the queue + if (len) { + to_queue = uxQueueSpacesAvailable(i2c->tx_queue); + if (len < to_queue) { + to_queue = len; } - i2c_ll_write_txfifo(i2c->dev, (uint8_t *)buf, to_fifo); - buf += to_fifo; - len -= to_fifo; - //reset tx_queue - xQueueReset(i2c->tx_queue); - //write the rest of the bytes to the queue - if (len) { - to_queue = uxQueueSpacesAvailable(i2c->tx_queue); - if (len < to_queue) { - to_queue = len; - } - for (size_t i = 0; i < to_queue; i++) { - if (xQueueSend(i2c->tx_queue, &buf[i], timeout_ms / portTICK_PERIOD_MS) != pdTRUE) { - xQueueReset(i2c->tx_queue); - to_queue = 0; - break; - } - } - //no need to enable TX_EMPTY if tx_queue is empty - if (to_queue) { - i2c_ll_slave_enable_tx_it(i2c->dev); + for (size_t i = 0; i < to_queue; i++) { + if (xQueueSend(i2c->tx_queue, &buf[i], timeout_ms / portTICK_PERIOD_MS) != pdTRUE) { + xQueueReset(i2c->tx_queue); + to_queue = 0; + break; } } + //no need to enable TX_EMPTY if tx_queue is empty + if (to_queue) { + i2c_ll_slave_enable_tx_it(i2c->dev); + } } - I2C_SLAVE_MUTEX_UNLOCK(); - return to_queue + to_fifo; } + I2C_SLAVE_MUTEX_UNLOCK(); + return to_queue + to_fifo; +} - //===================================================================================================================== - //-------------------------------------- Private Functions ------------------------------------------------------------ - //===================================================================================================================== +//===================================================================================================================== +//-------------------------------------- Private Functions ------------------------------------------------------------ +//===================================================================================================================== - static void i2c_slave_free_resources(i2c_slave_struct_t * i2c) { - i2c_slave_detach_gpio(i2c); - i2c_ll_set_slave_addr(i2c->dev, 0, false); - i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); - i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK); +static void i2c_slave_free_resources(i2c_slave_struct_t *i2c) { + i2c_slave_detach_gpio(i2c); + i2c_ll_set_slave_addr(i2c->dev, 0, false); + i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); + i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK); - if (i2c->intr_handle) { - esp_intr_free(i2c->intr_handle); - i2c->intr_handle = NULL; - } + if (i2c->intr_handle) { + esp_intr_free(i2c->intr_handle); + i2c->intr_handle = NULL; + } - if (i2c->task_handle) { - vTaskDelete(i2c->task_handle); - i2c->task_handle = NULL; - } + if (i2c->task_handle) { + vTaskDelete(i2c->task_handle); + i2c->task_handle = NULL; + } #if I2C_SLAVE_USE_RX_QUEUE - if (i2c->rx_queue) { - vQueueDelete(i2c->rx_queue); - i2c->rx_queue = NULL; - } + if (i2c->rx_queue) { + vQueueDelete(i2c->rx_queue); + i2c->rx_queue = NULL; + } #else if (i2c->rx_ring_buf) { vRingbufferDelete(i2c->rx_ring_buf); @@ -517,202 +515,202 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t } #endif - if (i2c->tx_queue) { - vQueueDelete(i2c->tx_queue); - i2c->tx_queue = NULL; - } - - if (i2c->event_queue) { - vQueueDelete(i2c->event_queue); - i2c->event_queue = NULL; - } + if (i2c->tx_queue) { + vQueueDelete(i2c->tx_queue); + i2c->tx_queue = NULL; + } - i2c->rx_data_count = 0; + if (i2c->event_queue) { + vQueueDelete(i2c->event_queue); + i2c->event_queue = NULL; } - static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed) { - if (i2c == NULL) { - log_e("no control buffer"); - return false; - } - if (clk_speed > 1100000UL) { - clk_speed = 1100000UL; - } + i2c->rx_data_count = 0; +} + +static bool i2c_slave_set_frequency(i2c_slave_struct_t *i2c, uint32_t clk_speed) { + if (i2c == NULL) { + log_e("no control buffer"); + return false; + } + if (clk_speed > 1100000UL) { + clk_speed = 1100000UL; + } - // Adjust Fifo thresholds based on frequency - uint32_t a = (clk_speed / 50000L) + 2; - log_d("Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d", SOC_I2C_FIFO_LEN - a, a); + // Adjust Fifo thresholds based on frequency + uint32_t a = (clk_speed / 50000L) + 2; + log_d("Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d", SOC_I2C_FIFO_LEN - a, a); - i2c_hal_clk_config_t clk_cal; + i2c_hal_clk_config_t clk_cal; #if SOC_I2C_SUPPORT_APB - i2c_ll_master_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal); - I2C_CLOCK_SRC_ATOMIC() { - i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_APB); /*!< I2C source clock from APB, 80M*/ - } + i2c_ll_master_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal); + I2C_CLOCK_SRC_ATOMIC() { + i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_APB); /*!< I2C source clock from APB, 80M*/ + } #elif SOC_I2C_SUPPORT_XTAL i2c_ll_master_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal); I2C_CLOCK_SRC_ATOMIC() { i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_XTAL); /*!< I2C source clock from XTAL, 40M */ } #endif - i2c_ll_set_txfifo_empty_thr(i2c->dev, a); - i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a); - i2c_ll_master_set_bus_timing(i2c->dev, &clk_cal); - i2c_ll_master_set_filter(i2c->dev, 3); - return true; - } + i2c_ll_set_txfifo_empty_thr(i2c->dev, a); + i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a); + i2c_ll_master_set_bus_timing(i2c->dev, &clk_cal); + i2c_ll_master_set_filter(i2c->dev, 3); + return true; +} - static void i2c_slave_delay_us(uint64_t us) { - uint64_t m = esp_timer_get_time(); - if (us) { - uint64_t e = (m + us); - if (m > e) { //overflow - while ((uint64_t)esp_timer_get_time() > e); - } - while ((uint64_t)esp_timer_get_time() < e); +static void i2c_slave_delay_us(uint64_t us) { + uint64_t m = esp_timer_get_time(); + if (us) { + uint64_t e = (m + us); + if (m > e) { //overflow + while ((uint64_t)esp_timer_get_time() > e); } + while ((uint64_t)esp_timer_get_time() < e); } +} - static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode) { - gpio_config_t conf = { - .pin_bit_mask = 1LL << pin, .mode = mode, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE - }; - gpio_config(&conf); - } +static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode) { + gpio_config_t conf = { + .pin_bit_mask = 1LL << pin, .mode = mode, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&conf); +} - static bool i2c_slave_check_line_state(int8_t sda, int8_t scl) { - if (sda < 0 || scl < 0) { - return false; //return false since there is nothing to do - } - // if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles - gpio_set_level(sda, 1); - gpio_set_level(scl, 1); - i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); - i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); - gpio_set_level(scl, 1); - - if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state - log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl)); - for (uint8_t a = 0; a < 9; a++) { +static bool i2c_slave_check_line_state(int8_t sda, int8_t scl) { + if (sda < 0 || scl < 0) { + return false; //return false since there is nothing to do + } + // if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles + gpio_set_level(sda, 1); + gpio_set_level(scl, 1); + i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); + i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); + gpio_set_level(scl, 1); + + if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state + log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl)); + for (uint8_t a = 0; a < 9; a++) { + i2c_slave_delay_us(5); + if (gpio_get_level(sda) && gpio_get_level(scl)) { // bus recovered + log_w("Recovered after %d Cycles", a); + gpio_set_level(sda, 0); // start i2c_slave_delay_us(5); - if (gpio_get_level(sda) && gpio_get_level(scl)) { // bus recovered - log_w("Recovered after %d Cycles", a); - gpio_set_level(sda, 0); // start - i2c_slave_delay_us(5); - for (uint8_t a = 0; a < 9; a++) { - gpio_set_level(scl, 1); - i2c_slave_delay_us(5); - gpio_set_level(scl, 0); - i2c_slave_delay_us(5); - } + for (uint8_t a = 0; a < 9; a++) { gpio_set_level(scl, 1); i2c_slave_delay_us(5); - gpio_set_level(sda, 1); // stop - break; + gpio_set_level(scl, 0); + i2c_slave_delay_us(5); } - gpio_set_level(scl, 0); - i2c_slave_delay_us(5); gpio_set_level(scl, 1); + i2c_slave_delay_us(5); + gpio_set_level(sda, 1); // stop + break; } + gpio_set_level(scl, 0); + i2c_slave_delay_us(5); + gpio_set_level(scl, 1); } + } - if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state - log_e("Bus Invalid State, Can't init sda=%d, scl=%d", gpio_get_level(sda), gpio_get_level(scl)); - return false; // bus is busy - } - return true; + if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state + log_e("Bus Invalid State, Can't init sda=%d, scl=%d", gpio_get_level(sda), gpio_get_level(scl)); + return false; // bus is busy } + return true; +} - static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl) { - if (i2c == NULL) { - log_e("no control block"); - return false; - } +static bool i2c_slave_attach_gpio(i2c_slave_struct_t *i2c, int8_t sda, int8_t scl) { + if (i2c == NULL) { + log_e("no control block"); + return false; + } - if ((sda < 0) || (scl < 0)) { - log_e("bad pins sda=%d, scl=%d", sda, scl); - return false; - } + if ((sda < 0) || (scl < 0)) { + log_e("bad pins sda=%d, scl=%d", sda, scl); + return false; + } - i2c->scl = scl; - gpio_set_level(scl, 1); - i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT_OUTPUT_OD); - gpio_matrix_out(scl, I2C_SCL_IDX(i2c->num), false, false); - gpio_matrix_in(scl, I2C_SCL_IDX(i2c->num), false); + i2c->scl = scl; + gpio_set_level(scl, 1); + i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_matrix_out(scl, I2C_SCL_IDX(i2c->num), false, false); + gpio_matrix_in(scl, I2C_SCL_IDX(i2c->num), false); - i2c->sda = sda; - gpio_set_level(sda, 1); - i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT_OUTPUT_OD); - gpio_matrix_out(sda, I2C_SDA_IDX(i2c->num), false, false); - gpio_matrix_in(sda, I2C_SDA_IDX(i2c->num), false); + i2c->sda = sda; + gpio_set_level(sda, 1); + i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_matrix_out(sda, I2C_SDA_IDX(i2c->num), false, false); + gpio_matrix_in(sda, I2C_SDA_IDX(i2c->num), false); - return true; + return true; +} + +static bool i2c_slave_detach_gpio(i2c_slave_struct_t *i2c) { + if (i2c == NULL) { + log_e("no control Block"); + return false; + } + if (i2c->scl >= 0) { + gpio_matrix_out(i2c->scl, 0x100, false, false); + gpio_matrix_in(0x30, I2C_SCL_IDX(i2c->num), false); + i2c_slave_gpio_mode(i2c->scl, GPIO_MODE_INPUT); + i2c->scl = -1; // un attached } + if (i2c->sda >= 0) { + gpio_matrix_out(i2c->sda, 0x100, false, false); + gpio_matrix_in(0x30, I2C_SDA_IDX(i2c->num), false); + i2c_slave_gpio_mode(i2c->sda, GPIO_MODE_INPUT); + i2c->sda = -1; // un attached + } + return true; +} - static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c) { - if (i2c == NULL) { - log_e("no control Block"); - return false; - } - if (i2c->scl >= 0) { - gpio_matrix_out(i2c->scl, 0x100, false, false); - gpio_matrix_in(0x30, I2C_SCL_IDX(i2c->num), false); - i2c_slave_gpio_mode(i2c->scl, GPIO_MODE_INPUT); - i2c->scl = -1; // un attached +static bool i2c_slave_send_event(i2c_slave_struct_t *i2c, i2c_slave_queue_event_t *event) { + bool pxHigherPriorityTaskWoken = false; + if (i2c->event_queue) { + if (xQueueSendFromISR(i2c->event_queue, event, (BaseType_t *const)&pxHigherPriorityTaskWoken) != pdTRUE) { + //log_e("event_queue_full"); } - if (i2c->sda >= 0) { - gpio_matrix_out(i2c->sda, 0x100, false, false); - gpio_matrix_in(0x30, I2C_SDA_IDX(i2c->num), false); - i2c_slave_gpio_mode(i2c->sda, GPIO_MODE_INPUT); - i2c->sda = -1; // un attached - } - return true; } + return pxHigherPriorityTaskWoken; +} - static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t * event) { - bool pxHigherPriorityTaskWoken = false; - if (i2c->event_queue) { - if (xQueueSendFromISR(i2c->event_queue, event, (BaseType_t *const)&pxHigherPriorityTaskWoken) != pdTRUE) { - //log_e("event_queue_full"); - } - } - return pxHigherPriorityTaskWoken; - } - - static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c) { - bool pxHigherPriorityTaskWoken = false; - uint32_t d = 0, moveCnt = 0; - i2c_ll_get_txfifo_len(i2c->dev, &moveCnt); - while (moveCnt > 0) { // read tx queue until Fifo is full or queue is empty - if (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) == pdTRUE) { - i2c_ll_write_txfifo(i2c->dev, (uint8_t *)&d, 1); - moveCnt--; - } else { - i2c_ll_slave_disable_tx_it(i2c->dev); - break; - } +static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t *i2c) { + bool pxHigherPriorityTaskWoken = false; + uint32_t d = 0, moveCnt = 0; + i2c_ll_get_txfifo_len(i2c->dev, &moveCnt); + while (moveCnt > 0) { // read tx queue until Fifo is full or queue is empty + if (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) == pdTRUE) { + i2c_ll_write_txfifo(i2c->dev, (uint8_t *)&d, 1); + moveCnt--; + } else { + i2c_ll_slave_disable_tx_it(i2c->dev); + break; } - return pxHigherPriorityTaskWoken; } + return pxHigherPriorityTaskWoken; +} - static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len) { +static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t *i2c, uint32_t len) { #if I2C_SLAVE_USE_RX_QUEUE - uint32_t d = 0; + uint32_t d = 0; #else uint8_t data[SOC_I2C_FIFO_LEN]; #endif - bool pxHigherPriorityTaskWoken = false; + bool pxHigherPriorityTaskWoken = false; #if I2C_SLAVE_USE_RX_QUEUE - while (len > 0) { - i2c_ll_read_rxfifo(i2c->dev, (uint8_t *)&d, 1); - if (xQueueSendFromISR(i2c->rx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) != pdTRUE) { - log_e("rx_queue_full"); - } else { - i2c->rx_data_count++; - } - if (--len == 0) { - len = i2c_ll_get_rxfifo_cnt(i2c->dev); - } + while (len > 0) { + i2c_ll_read_rxfifo(i2c->dev, (uint8_t *)&d, 1); + if (xQueueSendFromISR(i2c->rx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) != pdTRUE) { + log_e("rx_queue_full"); + } else { + i2c->rx_data_count++; + } + if (--len == 0) { + len = i2c_ll_get_rxfifo_cnt(i2c->dev); + } #else if (len) { i2c_ll_read_rxfifo(i2c->dev, data, len); @@ -722,109 +720,109 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t i2c->rx_data_count += len; } #endif - } - return pxHigherPriorityTaskWoken; } + return pxHigherPriorityTaskWoken; +} + +static void i2c_slave_isr_handler(void *arg) { + bool pxHigherPriorityTaskWoken = false; + i2c_slave_struct_t *i2c = (i2c_slave_struct_t *)arg; // recover data - static void i2c_slave_isr_handler(void *arg) { - bool pxHigherPriorityTaskWoken = false; - i2c_slave_struct_t *i2c = (i2c_slave_struct_t *)arg; // recover data + uint32_t activeInt = 0; + i2c_ll_get_intr_mask(i2c->dev, &activeInt); + i2c_ll_clear_intr_mask(i2c->dev, activeInt); + uint32_t rx_fifo_len = 0; + i2c_ll_get_rxfifo_cnt(i2c->dev, &rx_fifo_len); + bool slave_rw = i2c_ll_slave_rw(i2c->dev); - uint32_t activeInt = 0; - i2c_ll_get_intr_mask(i2c->dev, &activeInt); - i2c_ll_clear_intr_mask(i2c->dev, activeInt); - uint32_t rx_fifo_len = 0; - i2c_ll_get_rxfifo_cnt(i2c->dev, &rx_fifo_len); - bool slave_rw = i2c_ll_slave_rw(i2c->dev); + if (activeInt & I2C_RXFIFO_WM_INT_ENA) { // RX FiFo Full + pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + i2c_ll_slave_enable_rx_it(i2c->dev); //is this necessary? + } - if (activeInt & I2C_RXFIFO_WM_INT_ENA) { // RX FiFo Full + if (activeInt & I2C_TRANS_COMPLETE_INT_ENA) { // STOP + if (rx_fifo_len) { //READ RX FIFO pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); - i2c_ll_slave_enable_rx_it(i2c->dev); //is this necessary? } - - if (activeInt & I2C_TRANS_COMPLETE_INT_ENA) { // STOP - if (rx_fifo_len) { //READ RX FIFO - pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); - } - if (i2c->rx_data_count) { //WRITE or RepeatedStart - //SEND RX Event + if (i2c->rx_data_count) { //WRITE or RepeatedStart + //SEND RX Event + i2c_slave_queue_event_t event; + event.event = I2C_SLAVE_EVT_RX; + event.stop = !slave_rw; + event.param = i2c->rx_data_count; + pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); + //Zero RX count + i2c->rx_data_count = 0; + } + if (slave_rw) { // READ +#if CONFIG_IDF_TARGET_ESP32 + if (i2c->dev->status_reg.scl_main_state_last == 6) { + //SEND TX Event i2c_slave_queue_event_t event; - event.event = I2C_SLAVE_EVT_RX; - event.stop = !slave_rw; - event.param = i2c->rx_data_count; + event.event = I2C_SLAVE_EVT_TX; pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); - //Zero RX count - i2c->rx_data_count = 0; } - if (slave_rw) { // READ -#if CONFIG_IDF_TARGET_ESP32 - if (i2c->dev->status_reg.scl_main_state_last == 6) { - //SEND TX Event - i2c_slave_queue_event_t event; - event.event = I2C_SLAVE_EVT_TX; - pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); - } #else //reset TX data i2c_ll_txfifo_rst(i2c->dev); uint8_t d; while (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t *const)&pxHigherPriorityTaskWoken) == pdTRUE); //flush partial write #endif - } } + } #ifndef CONFIG_IDF_TARGET_ESP32 - if (activeInt & I2C_SLAVE_STRETCH_INT_ENA) { // STRETCH - i2c_stretch_cause_t cause = i2c_ll_stretch_cause(i2c->dev); - if (cause == I2C_STRETCH_CAUSE_MASTER_READ) { - //on C3 RX data disappears with repeated start, so we need to get it here - if (rx_fifo_len) { - pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); - } - //SEND TX Event - i2c_slave_queue_event_t event; - event.event = I2C_SLAVE_EVT_TX; - pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); - //will clear after execution - } else if (cause == I2C_STRETCH_CAUSE_TX_FIFO_EMPTY) { - pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); - i2c_ll_stretch_clr(i2c->dev); - } else if (cause == I2C_STRETCH_CAUSE_RX_FIFO_FULL) { + if (activeInt & I2C_SLAVE_STRETCH_INT_ENA) { // STRETCH + i2c_stretch_cause_t cause = i2c_ll_stretch_cause(i2c->dev); + if (cause == I2C_STRETCH_CAUSE_MASTER_READ) { + //on C3 RX data disappears with repeated start, so we need to get it here + if (rx_fifo_len) { pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); - i2c_ll_stretch_clr(i2c->dev); } + //SEND TX Event + i2c_slave_queue_event_t event; + event.event = I2C_SLAVE_EVT_TX; + pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); + //will clear after execution + } else if (cause == I2C_STRETCH_CAUSE_TX_FIFO_EMPTY) { + pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); + i2c_ll_stretch_clr(i2c->dev); + } else if (cause == I2C_STRETCH_CAUSE_RX_FIFO_FULL) { + pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + i2c_ll_stretch_clr(i2c->dev); } + } #endif - if (activeInt & I2C_TXFIFO_WM_INT_ENA) { // TX FiFo Empty - pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); - } + if (activeInt & I2C_TXFIFO_WM_INT_ENA) { // TX FiFo Empty + pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); + } - if (pxHigherPriorityTaskWoken) { - portYIELD_FROM_ISR(); - } + if (pxHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); } +} - static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len) { - if (!len) { - return 0; - } +static size_t i2c_slave_read_rx(i2c_slave_struct_t *i2c, uint8_t *data, size_t len) { + if (!len) { + return 0; + } #if I2C_SLAVE_USE_RX_QUEUE - uint8_t d = 0; - BaseType_t res = pdTRUE; - for (size_t i = 0; i < len; i++) { - if (data) { - res = xQueueReceive(i2c->rx_queue, &data[i], 0); - } else { - res = xQueueReceive(i2c->rx_queue, &d, 0); - } - if (res != pdTRUE) { - log_e("Read Queue(%u) Failed", i); - len = i; - break; - } + uint8_t d = 0; + BaseType_t res = pdTRUE; + for (size_t i = 0; i < len; i++) { + if (data) { + res = xQueueReceive(i2c->rx_queue, &data[i], 0); + } else { + res = xQueueReceive(i2c->rx_queue, &d, 0); + } + if (res != pdTRUE) { + log_e("Read Queue(%u) Failed", i); + len = i; + break; } - return (data) ? len : 0; + } + return (data) ? len : 0; #else size_t dlen = 0, to_read = len, so_far = 0, available = 0; uint8_t *rx_data = NULL; @@ -851,55 +849,55 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t } return (data) ? so_far : 0; #endif - } +} - static void i2c_slave_task(void *pv_args) { - i2c_slave_struct_t *i2c = (i2c_slave_struct_t *)pv_args; - i2c_slave_queue_event_t event; - size_t len = 0; - bool stop = false; - uint8_t *data = NULL; - for (;;) { - if (xQueueReceive(i2c->event_queue, &event, portMAX_DELAY) == pdTRUE) { - // Write - if (event.event == I2C_SLAVE_EVT_RX) { - len = event.param; - stop = event.stop; - data = (len > 0) ? (uint8_t *)malloc(len) : NULL; - - if (len && data == NULL) { - log_e("Malloc (%u) Failed", len); - } - len = i2c_slave_read_rx(i2c, data, len); - if (i2c->receive_callback) { - i2c->receive_callback(i2c->num, data, len, stop, i2c->arg); - } - free(data); - - // Read - } else if (event.event == I2C_SLAVE_EVT_TX) { - if (i2c->request_callback) { - i2c->request_callback(i2c->num, i2c->arg); - } - i2c_ll_stretch_clr(i2c->dev); +static void i2c_slave_task(void *pv_args) { + i2c_slave_struct_t *i2c = (i2c_slave_struct_t *)pv_args; + i2c_slave_queue_event_t event; + size_t len = 0; + bool stop = false; + uint8_t *data = NULL; + for (;;) { + if (xQueueReceive(i2c->event_queue, &event, portMAX_DELAY) == pdTRUE) { + // Write + if (event.event == I2C_SLAVE_EVT_RX) { + len = event.param; + stop = event.stop; + data = (len > 0) ? (uint8_t *)malloc(len) : NULL; + + if (len && data == NULL) { + log_e("Malloc (%u) Failed", len); } + len = i2c_slave_read_rx(i2c, data, len); + if (i2c->receive_callback) { + i2c->receive_callback(i2c->num, data, len, stop, i2c->arg); + } + free(data); + + // Read + } else if (event.event == I2C_SLAVE_EVT_TX) { + if (i2c->request_callback) { + i2c->request_callback(i2c->num, i2c->arg); + } + i2c_ll_stretch_clr(i2c->dev); } } - vTaskDelete(NULL); } + vTaskDelete(NULL); +} - static bool i2cSlaveDetachBus(void *bus_i2c_num) { - uint8_t num = (int)bus_i2c_num - 1; - i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; - if (i2c->scl == -1 && i2c->sda == -1) { - return true; - } - esp_err_t err = i2cSlaveDeinit(num); - if (err != ESP_OK) { - log_e("i2cSlaveDeinit failed with error: %d", err); - return false; - } +static bool i2cSlaveDetachBus(void *bus_i2c_num) { + uint8_t num = (int)bus_i2c_num - 1; + i2c_slave_struct_t *i2c = &_i2c_bus_array[num]; + if (i2c->scl == -1 && i2c->sda == -1) { return true; } + esp_err_t err = i2cSlaveDeinit(num); + if (err != ESP_OK) { + log_e("i2cSlaveDeinit failed with error: %d", err); + return false; + } + return true; +} #endif /* SOC_I2C_SUPPORT_SLAVE */ diff --git a/cores/esp32/esp32-hal-spi.c b/cores/esp32/esp32-hal-spi.c index 8c8ce0b7705..af3fd7b5f06 100644 --- a/cores/esp32/esp32-hal-spi.c +++ b/cores/esp32/esp32-hal-spi.c @@ -148,13 +148,15 @@ struct spi_struct_t { #if CONFIG_DISABLE_HAL_LOCKS #define SPI_MUTEX_LOCK() #define SPI_MUTEX_UNLOCK() -+ static spi_t _spi_bus_array[] = { +// clang-format off +static spi_t _spi_bus_array[] = { #if CONFIG_IDF_TARGET_ESP32S2 {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2, -1, -1, -1, -1} #elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 - {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1} + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1} #elif CONFIG_IDF_TARGET_ESP32C2 {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} #elif CONFIG_IDF_TARGET_ESP32C3 @@ -168,6 +170,7 @@ struct spi_struct_t { {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3, -1, -1, -1, -1} #endif }; +// clang-format on #else #define SPI_MUTEX_LOCK() \ do { \ diff --git a/cores/esp32/esp32-hal-touch.c b/cores/esp32/esp32-hal-touch.c index 4c0ed92656c..93e0cb1c4ac 100644 --- a/cores/esp32/esp32-hal-touch.c +++ b/cores/esp32/esp32-hal-touch.c @@ -29,7 +29,7 @@ #if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 static uint16_t __touchSleepCycles = 0x1000; static uint16_t __touchMeasureCycles = 0x1000; -#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 +#elif SOC_TOUCH_SENSOR_VERSION >= 2 // ESP32S2, ESP32S3, ESP32P4 static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT; static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT; #endif diff --git a/libraries/BLE/examples/BLE5_multi_advertising/ci.json b/libraries/BLE/examples/BLE5_multi_advertising/ci.json index fc9f75986fe..e97e4cf7fea 100644 --- a/libraries/BLE/examples/BLE5_multi_advertising/ci.json +++ b/libraries/BLE/examples/BLE5_multi_advertising/ci.json @@ -1,5 +1,6 @@ { "targets": { + "esp32": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json index a034e239a3f..e97e4cf7fea 100644 --- a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json +++ b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json @@ -1,10 +1,7 @@ { "targets": { "esp32": false, - "esp32c2": false, - "esp32c3": false, "esp32p4": false, - "esp32s2": false, - "esp32s3": false + "esp32s2": false } } diff --git a/libraries/BLE/examples/BLE5_periodic_sync/ci.json b/libraries/BLE/examples/BLE5_periodic_sync/ci.json index 715becda6cb..e97e4cf7fea 100644 --- a/libraries/BLE/examples/BLE5_periodic_sync/ci.json +++ b/libraries/BLE/examples/BLE5_periodic_sync/ci.json @@ -1,9 +1,6 @@ { "targets": { "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/BLE/examples/Beacon_Scanner/ci.json b/libraries/BLE/examples/Beacon_Scanner/ci.json index ee810400be6..fc9f75986fe 100644 --- a/libraries/BLE/examples/Beacon_Scanner/ci.json +++ b/libraries/BLE/examples/Beacon_Scanner/ci.json @@ -1,8 +1,5 @@ { "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/BLE/examples/Client/ci.json b/libraries/BLE/examples/Client/ci.json index eb6596c4a37..fc9f75986fe 100644 --- a/libraries/BLE/examples/Client/ci.json +++ b/libraries/BLE/examples/Client/ci.json @@ -1,6 +1,5 @@ { "targets": { - "esp32c3": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/BLE/examples/Notify/ci.json b/libraries/BLE/examples/Notify/ci.json index 156dda6560c..fc9f75986fe 100644 --- a/libraries/BLE/examples/Notify/ci.json +++ b/libraries/BLE/examples/Notify/ci.json @@ -1,6 +1,5 @@ { "targets": { - "esp32h2": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/BLE/examples/Server/ci.json b/libraries/BLE/examples/Server/ci.json index a034e239a3f..fc9f75986fe 100644 --- a/libraries/BLE/examples/Server/ci.json +++ b/libraries/BLE/examples/Server/ci.json @@ -1,10 +1,6 @@ { "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, "esp32p4": false, - "esp32s2": false, - "esp32s3": false + "esp32s2": false } } diff --git a/libraries/BLE/examples/Server_multiconnect/ci.json b/libraries/BLE/examples/Server_multiconnect/ci.json index 715becda6cb..fc9f75986fe 100644 --- a/libraries/BLE/examples/Server_multiconnect/ci.json +++ b/libraries/BLE/examples/Server_multiconnect/ci.json @@ -1,9 +1,5 @@ { "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/BLE/examples/UART/ci.json b/libraries/BLE/examples/UART/ci.json index ee810400be6..fc9f75986fe 100644 --- a/libraries/BLE/examples/UART/ci.json +++ b/libraries/BLE/examples/UART/ci.json @@ -1,8 +1,5 @@ { "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/BLE/examples/Write/ci.json b/libraries/BLE/examples/Write/ci.json index eb6596c4a37..fc9f75986fe 100644 --- a/libraries/BLE/examples/Write/ci.json +++ b/libraries/BLE/examples/Write/ci.json @@ -1,6 +1,5 @@ { "targets": { - "esp32c3": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/BLE/examples/iBeacon/ci.json b/libraries/BLE/examples/iBeacon/ci.json index 156dda6560c..fc9f75986fe 100644 --- a/libraries/BLE/examples/iBeacon/ci.json +++ b/libraries/BLE/examples/iBeacon/ci.json @@ -1,6 +1,5 @@ { "targets": { - "esp32h2": false, "esp32p4": false, "esp32s2": false } diff --git a/libraries/ESP32/examples/DeepSleep/TouchWakeUp/ci.json b/libraries/ESP32/examples/DeepSleep/TouchWakeUp/ci.json index 25c42144223..cd679adefad 100644 --- a/libraries/ESP32/examples/DeepSleep/TouchWakeUp/ci.json +++ b/libraries/ESP32/examples/DeepSleep/TouchWakeUp/ci.json @@ -2,6 +2,7 @@ "targets": { "esp32c3": false, "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP32/examples/Touch/TouchButton/ci.json b/libraries/ESP32/examples/Touch/TouchButton/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/ESP32/examples/Touch/TouchButton/ci.json +++ b/libraries/ESP32/examples/Touch/TouchButton/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/ESP32/examples/Touch/TouchButtonV2/ci.json b/libraries/ESP32/examples/Touch/TouchButtonV2/ci.json index e7d65393dd6..d87f049685e 100644 --- a/libraries/ESP32/examples/Touch/TouchButtonV2/ci.json +++ b/libraries/ESP32/examples/Touch/TouchButtonV2/ci.json @@ -3,6 +3,7 @@ "esp32": false, "esp32c3": false, "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json b/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json index 25c42144223..cd679adefad 100644 --- a/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json +++ b/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json @@ -2,6 +2,7 @@ "targets": { "esp32c3": false, "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/ESP32/examples/Touch/TouchRead/ci.json b/libraries/ESP32/examples/Touch/TouchRead/ci.json index 25c42144223..cd679adefad 100644 --- a/libraries/ESP32/examples/Touch/TouchRead/ci.json +++ b/libraries/ESP32/examples/Touch/TouchRead/ci.json @@ -2,6 +2,7 @@ "targets": { "esp32c3": false, "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/libraries/Ethernet/examples/ETH_LAN8720/ci.json b/libraries/Ethernet/examples/ETH_LAN8720/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/Ethernet/examples/ETH_LAN8720/ci.json +++ b/libraries/Ethernet/examples/ETH_LAN8720/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/Ethernet/examples/ETH_TLK110/ci.json b/libraries/Ethernet/examples/ETH_TLK110/ci.json index 1af543242e3..6afa60f44c4 100644 --- a/libraries/Ethernet/examples/ETH_TLK110/ci.json +++ b/libraries/Ethernet/examples/ETH_TLK110/ci.json @@ -3,6 +3,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false, "esp32s3": false } diff --git a/libraries/OpenThread/examples/COAP/coap_switch/ci.json b/libraries/OpenThread/examples/COAP/coap_switch/ci.json index 715becda6cb..a034e239a3f 100644 --- a/libraries/OpenThread/examples/COAP/coap_switch/ci.json +++ b/libraries/OpenThread/examples/COAP/coap_switch/ci.json @@ -1,10 +1,10 @@ { "targets": { "esp32": false, + "esp32c2": false, "esp32c3": false, - "esp32c6": false, - "esp32h2": false, "esp32p4": false, - "esp32s2": false + "esp32s2": false, + "esp32s3": false } } diff --git a/libraries/OpenThread/examples/SimpleCLI/ci.json b/libraries/OpenThread/examples/SimpleCLI/ci.json index ee810400be6..a034e239a3f 100644 --- a/libraries/OpenThread/examples/SimpleCLI/ci.json +++ b/libraries/OpenThread/examples/SimpleCLI/ci.json @@ -1,9 +1,10 @@ { "targets": { + "esp32": false, + "esp32c2": false, "esp32c3": false, - "esp32c6": false, - "esp32h2": false, "esp32p4": false, - "esp32s2": false + "esp32s2": false, + "esp32s3": false } } diff --git a/libraries/OpenThread/examples/SimpleNode/ci.json b/libraries/OpenThread/examples/SimpleNode/ci.json index eb6596c4a37..a034e239a3f 100644 --- a/libraries/OpenThread/examples/SimpleNode/ci.json +++ b/libraries/OpenThread/examples/SimpleNode/ci.json @@ -1,7 +1,10 @@ { "targets": { + "esp32": false, + "esp32c2": false, "esp32c3": false, "esp32p4": false, - "esp32s2": false + "esp32s2": false, + "esp32s3": false } } diff --git a/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json b/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json index 156dda6560c..a034e239a3f 100644 --- a/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json +++ b/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json @@ -1,7 +1,10 @@ { "targets": { - "esp32h2": false, + "esp32": false, + "esp32c2": false, + "esp32c3": false, "esp32p4": false, - "esp32s2": false + "esp32s2": false, + "esp32s3": false } } diff --git a/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino b/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino index c73f6078c03..3d3d3e4e38e 100644 --- a/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino +++ b/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino @@ -39,7 +39,7 @@ #define HSPI_SS 15 #endif -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 #define VSPI FSPI #endif diff --git a/tests/validation/periman/ci.json b/tests/validation/periman/ci.json index accee2b2135..22ff71c54ff 100644 --- a/tests/validation/periman/ci.json +++ b/tests/validation/periman/ci.json @@ -2,5 +2,8 @@ "platforms": { "qemu": false, "wokwi": false + }, + "targets": { + "esp32p4": false } } diff --git a/tests/validation/touch/ci.json b/tests/validation/touch/ci.json index 8d58dbf5250..d3129f16bae 100644 --- a/tests/validation/touch/ci.json +++ b/tests/validation/touch/ci.json @@ -6,6 +6,7 @@ "targets": { "esp32c3": false, "esp32c6": false, - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index a68ef879659..e5fa0a8285f 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -100,7 +100,7 @@ void transmit_and_check_msg(const String msg_append, bool perform_assert = true) if (perform_assert) { TEST_ASSERT_EQUAL_STRING(("Hello from Serial1 (UART1) >>> via loopback >>> Serial1 (UART1) " + msg_append).c_str(), recv_msg.c_str()); } -#elif SOC_UART_HP_NUM == 3 +#elif SOC_UART_HP_NUM >= 3 Serial1.print("Hello from Serial1 (UART1) >>> to >>> Serial2 (UART2) " + msg_append); Serial1.flush(); delay(100); @@ -128,7 +128,7 @@ void task_delayed_msg(void *pvParameters) { #if SOC_UART_HP_NUM == 2 selected_serial = &Serial; -#elif SOC_UART_HP_NUM == 3 +#elif SOC_UART_HP_NUM >= 3 selected_serial = &Serial1; #endif @@ -150,7 +150,7 @@ void setUp(void) { onReceive_cb(Serial1); }); uart_internal_loopback(1, RX1); -#elif SOC_UART_HP_NUM == 3 +#elif SOC_UART_HP_NUM >= 3 log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)"); Serial1.onReceive([]() { @@ -225,7 +225,7 @@ void change_baudrate_test(void) { Serial1.updateBaudRate(9600); TEST_ASSERT_UINT_WITHIN(192, 9600, Serial1.baudRate()); -#if SOC_UART_HP_NUM == 3 +#if SOC_UART_HP_NUM >= 3 Serial2.updateBaudRate(9600); TEST_ASSERT_UINT_WITHIN(192, 9600, Serial2.baudRate()); #endif @@ -239,7 +239,7 @@ void change_baudrate_test(void) { //Baudrate error should be within 2% of the target baudrate TEST_ASSERT_UINT_WITHIN(2304, 115200, Serial1.baudRate()); -#if SOC_UART_HP_NUM == 3 +#if SOC_UART_HP_NUM >= 3 TEST_ASSERT_UINT_WITHIN(2304, 115200, Serial2.baudRate()); #endif @@ -421,7 +421,7 @@ void change_pins_test(void) { #if SOC_UART_HP_NUM == 2 esp_rom_gpio_connect_out_signal(SOC_RX0, SIG_GPIO_OUT_IDX, false, false); -#elif SOC_UART_HP_NUM == 3 +#elif SOC_UART_HP_NUM >= 3 esp_rom_gpio_connect_out_signal(RX1, SIG_GPIO_OUT_IDX, false, false); esp_rom_gpio_connect_out_signal(RX2, SIG_GPIO_OUT_IDX, false, false); #endif @@ -432,7 +432,7 @@ void change_pins_test(void) { Serial1.setPins(NEW_RX1, NEW_TX1); TEST_ASSERT_EQUAL(NEW_RX1, uart_get_RxPin(1)); TEST_ASSERT_EQUAL(NEW_TX1, uart_get_TxPin(1)); -#elif SOC_UART_HP_NUM == 3 +#elif SOC_UART_HP_NUM >= 3 Serial1.setPins(RX2, TX2); Serial2.setPins(RX1, TX1); TEST_ASSERT_EQUAL(RX2, uart_get_RxPin(1)); @@ -447,7 +447,7 @@ void change_pins_test(void) { #if SOC_UART_HP_NUM == 2 uart_internal_loopback(1, NEW_RX1); -#elif SOC_UART_HP_NUM == 3 +#elif SOC_UART_HP_NUM >= 3 uart_internal_loopback(1, RX1); uart_internal_loopback(2, RX2); #endif @@ -470,7 +470,7 @@ void auto_baudrate_test(void) { #if SOC_UART_HP_NUM == 2 selected_serial = &Serial1; uart_internal_loopback(0, RX1); -#elif SOC_UART_HP_NUM == 3 +#elif SOC_UART_HP_NUM >= 3 selected_serial = &Serial2; #endif @@ -504,7 +504,7 @@ void periman_test(void) { Wire.begin(RX1, TX1); -#if SOC_UART_HP_NUM == 3 +#if SOC_UART_HP_NUM >= 3 Wire1.begin(RX2, TX2); #endif @@ -518,7 +518,7 @@ void periman_test(void) { Serial1.setPins(RX1, TX1); -#if SOC_UART_HP_NUM == 3 +#if SOC_UART_HP_NUM >= 3 Serial2.setPins(RX2, TX2); uart_internal_loopback(1, RX2); uart_internal_loopback(2, RX1); @@ -577,7 +577,7 @@ void setup() { onReceive_cb(Serial1); }); uart_internal_loopback(1, RX1); -#elif SOC_UART_HP_NUM == 3 +#elif SOC_UART_HP_NUM >= 3 log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)"); Serial1.onReceive([]() { diff --git a/tests/validation/wifi/ci.json b/tests/validation/wifi/ci.json index ff2c1d7c9ce..a51b5669598 100644 --- a/tests/validation/wifi/ci.json +++ b/tests/validation/wifi/ci.json @@ -22,6 +22,7 @@ "qemu": false }, "targets": { - "esp32h2": false + "esp32h2": false, + "esp32p4": false } } diff --git a/variants/esp32p4/pins_arduino.h b/variants/esp32p4/pins_arduino.h index 87d0548cf3c..caba8995222 100644 --- a/variants/esp32p4/pins_arduino.h +++ b/variants/esp32p4/pins_arduino.h @@ -27,4 +27,34 @@ static const uint8_t MOSI = 11; static const uint8_t MISO = 12; static const uint8_t SCK = 13; +static const uint8_t A0 = 16; +static const uint8_t A1 = 17; +static const uint8_t A2 = 18; +static const uint8_t A3 = 19; +static const uint8_t A4 = 20; +static const uint8_t A5 = 21; +static const uint8_t A6 = 22; +static const uint8_t A7 = 23; +static const uint8_t A8 = 49; +static const uint8_t A9 = 50; +static const uint8_t A10 = 51; +static const uint8_t A11 = 52; +static const uint8_t A12 = 53; +static const uint8_t A13 = 54; + +static const uint8_t T0 = 2; +static const uint8_t T1 = 3; +static const uint8_t T2 = 4; +static const uint8_t T3 = 5; +static const uint8_t T4 = 6; +static const uint8_t T5 = 7; +static const uint8_t T6 = 8; +static const uint8_t T7 = 9; +static const uint8_t T8 = 10; +static const uint8_t T9 = 11; +static const uint8_t T10 = 12; +static const uint8_t T11 = 13; +static const uint8_t T12 = 14; +static const uint8_t T13 = 15; + #endif /* Pins_Arduino_h */ From 55bd1d5ee27706c46edeae4944ef534bb3a73a29 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Wed, 25 Sep 2024 22:47:08 +0200 Subject: [PATCH 015/406] digitalPinToInterrupt: fix double pin remapping (#10373) The digitalPinToInterrupt() macro currently remaps the pin number to the GPIO number. This is not necessary, as most users will then use the returned value in attachInterrupt() or other similar API functions, which already perform the same remapping. The first half of the macro (the condition) does indeed require the remapping to ensure the check operates on GPIO numbers. Fixes espressif/arduino-esp32#10367. --- cores/esp32/Arduino.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h index 4a92f29d0df..2b115505cff 100644 --- a/cores/esp32/Arduino.h +++ b/cores/esp32/Arduino.h @@ -142,7 +142,7 @@ #endif #define EXTERNAL_NUM_INTERRUPTS NUM_DIGITAL_PINS // All GPIOs #define analogInputToDigitalPin(p) (((p) < NUM_ANALOG_INPUTS) ? (analogChannelToDigitalPin(p)) : -1) -#define digitalPinToInterrupt(p) ((((uint8_t)digitalPinToGPIONumber(p)) < NUM_DIGITAL_PINS) ? digitalPinToGPIONumber(p) : NOT_AN_INTERRUPT) +#define digitalPinToInterrupt(p) ((((uint8_t)digitalPinToGPIONumber(p)) < NUM_DIGITAL_PINS) ? (p) : NOT_AN_INTERRUPT) #define digitalPinHasPWM(p) (((uint8_t)digitalPinToGPIONumber(p)) < NUM_DIGITAL_PINS) typedef bool boolean; From b05f18dad55609ae2a569be81c7535021b880cf3 Mon Sep 17 00:00:00 2001 From: vortigont Date: Thu, 26 Sep 2024 07:37:00 +0900 Subject: [PATCH 016/406] fix: DNSServer Lib - improper startup code in WiFi mode (#10366) * DNSServer: fix improper startup code in WiFi mode When running on WiFi-AP mode server's start() method returned true while in fact UDP listening socket was never created Regression introduced in #8760 Closes #10330 * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- .../DNSServer/examples/CaptivePortal/CaptivePortal.ino | 6 +++++- libraries/DNSServer/src/DNSServer.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino b/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino index f5de8aa9b57..d956dc14ad3 100644 --- a/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino +++ b/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino @@ -39,7 +39,11 @@ void setup() { // by default DNSServer is started serving any "*" domain name. It will reply // AccessPoint's IP to all DNS request (this is required for Captive Portal detection) - dnsServer.start(); + if (dnsServer.start()) { + Serial.println("Started DNS server in captive portal-mode"); + } else { + Serial.println("Err: Can't start DNS server!"); + } // serve a simple root page server.on("/", handleRoot); diff --git a/libraries/DNSServer/src/DNSServer.cpp b/libraries/DNSServer/src/DNSServer.cpp index 69e41092dc5..28cf89d6ede 100644 --- a/libraries/DNSServer/src/DNSServer.cpp +++ b/libraries/DNSServer/src/DNSServer.cpp @@ -22,10 +22,13 @@ bool DNSServer::start() { #if SOC_WIFI_SUPPORTED if (WiFi.getMode() & WIFI_AP) { _resolvedIP = WiFi.softAPIP(); - return true; + } else { + return false; // won't run if WiFi is not in AP mode, or no WiFi } +#else + return false; // for other non WiFi-AP networking an overloaded method must be used to get device's IP + // start(uint16_t port, const String &domainName, const IPAddress &resolvedIP) #endif - return false; // won't run if WiFi is not in AP mode } _udp.close(); From 1f1de2738b9cc93316bebffca592511760b0130a Mon Sep 17 00:00:00 2001 From: Guil-T Date: Mon, 30 Sep 2024 06:14:30 -0400 Subject: [PATCH 017/406] Added Sparkfun ESP32-S3 Thing Plus board (#10382) * Create pins_arduino.h * added board Sparkfun ESP32-S3 Thing Plus added board Sparkfun ESP32-S3 Thing Plus * readded last line of hashes in boards.txt * Update pins_arduino.h re-added SS pin to pass test * removed unapplicable flash configurations the sparkfun esp32-s3 thing plus * added sparkfun esp32-s3 thing plus removed commented code * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- boards.txt | 217 ++++++++++++++++++ .../pins_arduino.h | 61 +++++ 2 files changed, 278 insertions(+) create mode 100644 variants/sparkfun_esp32s3_thing_plus/pins_arduino.h diff --git a/boards.txt b/boards.txt index 88fb110b099..0e873f0110b 100644 --- a/boards.txt +++ b/boards.txt @@ -6904,6 +6904,223 @@ sparkfun_esp32s2_thing_plus.menu.EraseFlash.none.upload.erase_cmd= sparkfun_esp32s2_thing_plus.menu.EraseFlash.all=Enabled sparkfun_esp32s2_thing_plus.menu.EraseFlash.all.upload.erase_cmd=-e +############################################################## +# Sparkfun ESP32S3 Thing Plus + +sparkfun_esp32s3_thing_plus.name=SparkFun ESP32-S3 Thing Plus +sparkfun_esp32s3_thing_plus.bootloader.tool=esptool_py +sparkfun_esp32s3_thing_plus.bootloader.tool.default=esptool_py + +sparkfun_esp32s3_thing_plus.upload.tool=esptool_py +sparkfun_esp32s3_thing_plus.upload.tool.default=esptool_py +sparkfun_esp32s3_thing_plus.upload.tool.network=esp_ota + +sparkfun_esp32s3_thing_plus.upload.maximum_size=1310720 +sparkfun_esp32s3_thing_plus.upload.maximum_data_size=327680 +sparkfun_esp32s3_thing_plus.upload.flags= +sparkfun_esp32s3_thing_plus.upload.extra_flags= +sparkfun_esp32s3_thing_plus.upload.use_1200bps_touch=false +sparkfun_esp32s3_thing_plus.upload.wait_for_upload_port=false + +sparkfun_esp32s3_thing_plus.serial.disableDTR=false +sparkfun_esp32s3_thing_plus.serial.disableRTS=false + +sparkfun_esp32s3_thing_plus.build.tarch=xtensa +sparkfun_esp32s3_thing_plus.build.bootloader_addr=0x0 +sparkfun_esp32s3_thing_plus.build.target=esp32s3 +sparkfun_esp32s3_thing_plus.build.mcu=esp32s3 +sparkfun_esp32s3_thing_plus.build.core=esp32 +sparkfun_esp32s3_thing_plus.build.variant=sparkfun_esp32s3_thing_plus +sparkfun_esp32s3_thing_plus.build.board=SPARKFUN_ESP32S3_THING_PLUS + +sparkfun_esp32s3_thing_plus.build.usb_mode=1 +sparkfun_esp32s3_thing_plus.build.cdc_on_boot=0 +sparkfun_esp32s3_thing_plus.build.msc_on_boot=0 +sparkfun_esp32s3_thing_plus.build.dfu_on_boot=0 +sparkfun_esp32s3_thing_plus.build.f_cpu=240000000L +sparkfun_esp32s3_thing_plus.build.flash_size=4MB +sparkfun_esp32s3_thing_plus.build.flash_freq=80m +sparkfun_esp32s3_thing_plus.build.flash_mode=dio +sparkfun_esp32s3_thing_plus.build.boot=qio +sparkfun_esp32s3_thing_plus.build.boot_freq=80m +sparkfun_esp32s3_thing_plus.build.partitions=default +sparkfun_esp32s3_thing_plus.build.defines= +sparkfun_esp32s3_thing_plus.build.loop_core= +sparkfun_esp32s3_thing_plus.build.event_core= +sparkfun_esp32s3_thing_plus.build.psram_type=qspi +sparkfun_esp32s3_thing_plus.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.default=Disabled +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.default.build.copy_jtag_files=0 +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.builtin=Integrated USB JTAG +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.external=FTDI Adapter +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.external.build.copy_jtag_files=1 +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.bridge=ESP USB Bridge +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +sparkfun_esp32s3_thing_plus.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +sparkfun_esp32s3_thing_plus.menu.PSRAM.enabled=QSPI PSRAM +sparkfun_esp32s3_thing_plus.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +sparkfun_esp32s3_thing_plus.menu.PSRAM.enabled.build.psram_type=qspi + +sparkfun_esp32s3_thing_plus.menu.PSRAM.disabled=Disabled +sparkfun_esp32s3_thing_plus.menu.PSRAM.disabled.build.defines= +sparkfun_esp32s3_thing_plus.menu.PSRAM.disabled.build.psram_type=qspi +sparkfun_esp32s3_thing_plus.menu.PSRAM.opi=OPI PSRAM +sparkfun_esp32s3_thing_plus.menu.PSRAM.opi.build.defines=-DBOARD_HAS_PSRAM +sparkfun_esp32s3_thing_plus.menu.PSRAM.opi.build.psram_type=opi + +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio=QIO 80MHz +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio.build.flash_mode=dio +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio.build.boot=qio +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio.build.boot_freq=80m +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio.build.flash_freq=80m +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio120=QIO 120MHz +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio120.build.flash_mode=dio +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio120.build.boot=qio +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio120.build.boot_freq=120m +sparkfun_esp32s3_thing_plus.menu.FlashMode.qio120.build.flash_freq=80m +sparkfun_esp32s3_thing_plus.menu.FlashMode.dio=DIO 80MHz +sparkfun_esp32s3_thing_plus.menu.FlashMode.dio.build.flash_mode=dio +sparkfun_esp32s3_thing_plus.menu.FlashMode.dio.build.boot=dio +sparkfun_esp32s3_thing_plus.menu.FlashMode.dio.build.boot_freq=80m +sparkfun_esp32s3_thing_plus.menu.FlashMode.dio.build.flash_freq=80m + +sparkfun_esp32s3_thing_plus.menu.LoopCore.1=Core 1 +sparkfun_esp32s3_thing_plus.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +sparkfun_esp32s3_thing_plus.menu.LoopCore.0=Core 0 +sparkfun_esp32s3_thing_plus.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +sparkfun_esp32s3_thing_plus.menu.EventsCore.1=Core 1 +sparkfun_esp32s3_thing_plus.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +sparkfun_esp32s3_thing_plus.menu.EventsCore.0=Core 0 +sparkfun_esp32s3_thing_plus.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +sparkfun_esp32s3_thing_plus.menu.USBMode.default=Hardware CDC and JTAG +sparkfun_esp32s3_thing_plus.menu.USBMode.default.build.usb_mode=1 +sparkfun_esp32s3_thing_plus.menu.USBMode.hwcdc=USB-OTG (TinyUSB) +sparkfun_esp32s3_thing_plus.menu.USBMode.hwcdc.build.usb_mode=0 + +# sparkfun says to put that to Enabled but it fails +sparkfun_esp32s3_thing_plus.menu.CDCOnBoot.default=Disabled +sparkfun_esp32s3_thing_plus.menu.CDCOnBoot.default.build.cdc_on_boot=0 +sparkfun_esp32s3_thing_plus.menu.CDCOnBoot.cdc=Enabled +sparkfun_esp32s3_thing_plus.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +sparkfun_esp32s3_thing_plus.menu.MSCOnBoot.default=Disabled +sparkfun_esp32s3_thing_plus.menu.MSCOnBoot.default.build.msc_on_boot=0 +sparkfun_esp32s3_thing_plus.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +sparkfun_esp32s3_thing_plus.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +sparkfun_esp32s3_thing_plus.menu.DFUOnBoot.default=Disabled +sparkfun_esp32s3_thing_plus.menu.DFUOnBoot.default.build.dfu_on_boot=0 +sparkfun_esp32s3_thing_plus.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +sparkfun_esp32s3_thing_plus.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +sparkfun_esp32s3_thing_plus.menu.UploadMode.default=UART0 / Hardware CDC +sparkfun_esp32s3_thing_plus.menu.UploadMode.default.upload.use_1200bps_touch=false +sparkfun_esp32s3_thing_plus.menu.UploadMode.default.upload.wait_for_upload_port=false +sparkfun_esp32s3_thing_plus.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +sparkfun_esp32s3_thing_plus.menu.UploadMode.cdc.upload.use_1200bps_touch=true +sparkfun_esp32s3_thing_plus.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.default.build.partitions=default +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.minimal.build.partitions=minimal +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.no_fs.build.partitions=no_fs +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.no_ota.build.partitions=no_ota +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.huge_app.build.partitions=huge_app +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.rainmaker=RainMaker 4MB +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.custom=Custom +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.custom.build.partitions= +sparkfun_esp32s3_thing_plus.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +sparkfun_esp32s3_thing_plus.menu.CPUFreq.240=240MHz (WiFi) +sparkfun_esp32s3_thing_plus.menu.CPUFreq.240.build.f_cpu=240000000L +sparkfun_esp32s3_thing_plus.menu.CPUFreq.160=160MHz (WiFi) +sparkfun_esp32s3_thing_plus.menu.CPUFreq.160.build.f_cpu=160000000L +sparkfun_esp32s3_thing_plus.menu.CPUFreq.80=80MHz (WiFi) +sparkfun_esp32s3_thing_plus.menu.CPUFreq.80.build.f_cpu=80000000L +sparkfun_esp32s3_thing_plus.menu.CPUFreq.40=40MHz +sparkfun_esp32s3_thing_plus.menu.CPUFreq.40.build.f_cpu=40000000L +sparkfun_esp32s3_thing_plus.menu.CPUFreq.20=20MHz +sparkfun_esp32s3_thing_plus.menu.CPUFreq.20.build.f_cpu=20000000L +sparkfun_esp32s3_thing_plus.menu.CPUFreq.10=10MHz +sparkfun_esp32s3_thing_plus.menu.CPUFreq.10.build.f_cpu=10000000L + +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.921600=921600 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.921600.upload.speed=921600 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.115200=115200 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.115200.upload.speed=115200 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.256000.windows=256000 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.256000.upload.speed=256000 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.230400.windows.upload.speed=256000 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.230400=230400 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.230400.upload.speed=230400 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.460800.linux=460800 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.460800.macosx=460800 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.460800.upload.speed=460800 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.512000.windows=512000 +sparkfun_esp32s3_thing_plus.menu.UploadSpeed.512000.upload.speed=512000 + +sparkfun_esp32s3_thing_plus.menu.DebugLevel.none=None +sparkfun_esp32s3_thing_plus.menu.DebugLevel.none.build.code_debug=0 +sparkfun_esp32s3_thing_plus.menu.DebugLevel.error=Error +sparkfun_esp32s3_thing_plus.menu.DebugLevel.error.build.code_debug=1 +sparkfun_esp32s3_thing_plus.menu.DebugLevel.warn=Warn +sparkfun_esp32s3_thing_plus.menu.DebugLevel.warn.build.code_debug=2 +sparkfun_esp32s3_thing_plus.menu.DebugLevel.info=Info +sparkfun_esp32s3_thing_plus.menu.DebugLevel.info.build.code_debug=3 +sparkfun_esp32s3_thing_plus.menu.DebugLevel.debug=Debug +sparkfun_esp32s3_thing_plus.menu.DebugLevel.debug.build.code_debug=4 +sparkfun_esp32s3_thing_plus.menu.DebugLevel.verbose=Verbose +sparkfun_esp32s3_thing_plus.menu.DebugLevel.verbose.build.code_debug=5 + +sparkfun_esp32s3_thing_plus.menu.EraseFlash.none=Disabled +sparkfun_esp32s3_thing_plus.menu.EraseFlash.none.upload.erase_cmd= +sparkfun_esp32s3_thing_plus.menu.EraseFlash.all=Enabled +sparkfun_esp32s3_thing_plus.menu.EraseFlash.all.upload.erase_cmd=-e + +sparkfun_esp32s3_thing_plus.menu.ZigbeeMode.default=Disabled +sparkfun_esp32s3_thing_plus.menu.ZigbeeMode.default.build.zigbee_mode= +sparkfun_esp32s3_thing_plus.menu.ZigbeeMode.default.build.zigbee_libs= +sparkfun_esp32s3_thing_plus.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +sparkfun_esp32s3_thing_plus.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +sparkfun_esp32s3_thing_plus.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + ############################################################## sparkfun_esp32c6_thing_plus.name=SparkFun ESP32-C6 Thing Plus diff --git a/variants/sparkfun_esp32s3_thing_plus/pins_arduino.h b/variants/sparkfun_esp32s3_thing_plus/pins_arduino.h new file mode 100644 index 00000000000..7c5e0c1f570 --- /dev/null +++ b/variants/sparkfun_esp32s3_thing_plus/pins_arduino.h @@ -0,0 +1,61 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +//#define USB_VID 0x303A +//#define USB_PID 0x1001 +//#define USB_MANUFACTURER "Sparkfun" +//#define USB_PRODUCT "ESP32-S3 Thing Plus" +#define USB_SERIAL "" + +#define LED_PIN 46 //Pin 46 on Thing Plus C S3 is connected to WS2812 LED +#define COLOR_ORDER GRB +#define CHIPSET WS2812 +#define NUM_LEDS 1 +#define BRIGHTNESS 25 +#define LED_BUILTIN LED_PIN +#define BUILTIN_LED LED_BUILTIN // backward compatibility + +static const uint8_t LED = LED_PIN; +static const uint8_t STAT_LED = 0; +static const uint8_t BTN = 0; +static const uint8_t Q_EN = 45; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SS = 10; +static const uint8_t MISO = 13; //POCI +static const uint8_t MOSI = 11; //PICO +static const uint8_t SCK = 12; + +static const uint8_t SCL = 9; +static const uint8_t SDA = 8; + +static const uint8_t A0 = 10; +static const uint8_t A1 = 14; +static const uint8_t A2 = 15; +static const uint8_t A3 = 16; +static const uint8_t A4 = 17; +static const uint8_t A5 = 18; + +static const uint8_t GPIO0 = 21; +static const uint8_t GPIO1 = 7; +static const uint8_t GPIO2 = 6; +static const uint8_t GPIO3 = 5; +static const uint8_t GPIO4 = 4; +static const uint8_t GPIO5 = 2; +static const uint8_t GPIO6 = 1; + +static const uint8_t FREEBIE = 42; + +static const uint8_t SDIO_DET = 48; +static const uint8_t SDIO0 = 39; +static const uint8_t SDIO1 = 40; +static const uint8_t SDIO2 = 47; +static const uint8_t SDIO3 = 33; +static const uint8_t SDIO_CLK = 38; +static const uint8_t SDIO_CMD = 34; + +#endif /* Pins_Arduino_h */ From e403f0b4815643ccd2d98f62b7accf5a8108f2cd Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 30 Sep 2024 07:43:50 -0300 Subject: [PATCH 018/406] ci(json): Add configuration requirements to ci.json files (#10385) * ci(json): Add support for checking sdkconfig before running tests * docs(ci): Add explanation about requires field in JSON * fix(json): Ignore comments when searching requirements * feat(json): Add extended regex support to requires field * change(json): Move to using requirements in JSON * fix(json): Fix requirements for touch tests * refactor(json): Fix formatting of JSON files * fix(spi): Fix SPI example and JSON --- .github/scripts/install-platformio-esp32.sh | 47 +++++++++++++---- .github/scripts/sketch_utils.sh | 44 +++++++++++----- .github/scripts/tests_run.sh | 29 +++++++---- docs/en/contributing.rst | 52 +++++++++++++++---- .../ArduinoOTA/examples/BasicOTA/ci.json | 6 +-- .../AsyncUDP/examples/AsyncUDPClient/ci.json | 6 +-- .../examples/AsyncUDPMulticastServer/ci.json | 6 +-- .../AsyncUDP/examples/AsyncUDPServer/ci.json | 6 +-- .../BLE/examples/BLE5_extended_scan/ci.json | 7 ++- .../examples/BLE5_multi_advertising/ci.json | 7 ++- .../BLE5_periodic_advertising/ci.json | 7 ++- .../BLE/examples/BLE5_periodic_sync/ci.json | 7 ++- libraries/BLE/examples/Beacon_Scanner/ci.json | 6 +-- libraries/BLE/examples/Client/ci.json | 6 +-- .../BLE/examples/EddystoneTLM_Beacon/ci.json | 7 ++- .../BLE/examples/EddystoneURL_Beacon/ci.json | 7 ++- libraries/BLE/examples/Notify/ci.json | 6 +-- libraries/BLE/examples/Scan/ci.json | 6 +-- libraries/BLE/examples/Server/ci.json | 6 +-- .../BLE/examples/Server_multiconnect/ci.json | 6 +-- libraries/BLE/examples/UART/ci.json | 6 +-- libraries/BLE/examples/Write/ci.json | 6 +-- libraries/BLE/examples/iBeacon/ci.json | 6 +-- .../examples/DiscoverConnect/ci.json | 10 ++-- .../examples/GetLocalMAC/ci.json | 10 ++-- .../examples/SerialToSerialBT/ci.json | 10 ++-- .../examples/SerialToSerialBTM/ci.json | 10 ++-- .../examples/SerialToSerialBT_Legacy/ci.json | 10 ++-- .../examples/SerialToSerialBT_SSP/ci.json | 10 ++-- .../bt_classic_device_discovery/ci.json | 10 ++-- .../examples/bt_remove_paired_devices/ci.json | 10 ++-- .../DNSServer/examples/CaptivePortal/ci.json | 6 +-- .../examples/Camera/CameraWebServer/ci.json | 8 ++- libraries/ESP32/examples/HWCDC_Events/ci.json | 7 ++- .../ESP32/examples/Time/SimpleTime/ci.json | 6 +-- .../ESP32/examples/Touch/TouchButton/ci.json | 10 ++-- .../examples/Touch/TouchButtonV2/ci.json | 9 ++-- .../examples/Touch/TouchInterrupt/ci.json | 8 ++- .../ESP32/examples/Touch/TouchRead/ci.json | 8 ++- .../ESP_I2S/examples/ES8388_loopback/ci.json | 6 +++ .../ESP_I2S/examples/Record_to_WAV/ci.json | 10 ++-- .../ESP_I2S/examples/Simple_tone/ci.json | 5 ++ .../examples/ESP_NOW_Broadcast_Master/ci.json | 6 +-- .../examples/ESP_NOW_Broadcast_Slave/ci.json | 6 +-- .../ESP_NOW/examples/ESP_NOW_Network/ci.json | 6 +-- .../ESP_NOW/examples/ESP_NOW_Serial/ci.json | 6 +-- libraries/ESP_SR/examples/Basic/ci.json | 3 ++ .../ESPmDNS/examples/mDNS-SD_Extended/ci.json | 6 +-- .../ESPmDNS/examples/mDNS_Web_Server/ci.json | 6 +-- .../Ethernet/examples/ETH_LAN8720/ci.json | 10 ++-- .../Ethernet/examples/ETH_TLK110/ci.json | 10 ++-- .../Ethernet/examples/ETH_WIFI_BRIDGE/ci.json | 6 +-- libraries/FFat/examples/FFat_time/ci.json | 6 +-- .../HTTPClient/examples/Authorization/ci.json | 6 +-- .../examples/BasicHttpClient/ci.json | 6 +-- .../examples/BasicHttpsClient/ci.json | 6 +-- .../examples/HTTPClientEnterprise/ci.json | 6 +-- .../examples/ReuseConnection/ci.json | 6 +-- .../examples/StreamHttpClient/ci.json | 6 +-- .../HTTPUpdate/examples/httpUpdate/ci.json | 6 +-- .../examples/httpUpdateSPIFFS/ci.json | 6 +-- .../examples/httpUpdateSecure/ci.json | 6 +-- .../examples/WebUpdater/ci.json | 6 +-- .../examples/DiagnosticsSmokeTest/ci.json | 8 +-- .../examples/MinimalDiagnostics/ci.json | 8 +-- .../LittleFS/examples/LITTLEFS_time/ci.json | 6 +-- libraries/NetBIOS/examples/ESP_NBNST/ci.json | 6 +-- .../examples/WiFiClientInsecure/ci.json | 6 +-- .../examples/WiFiClientPSK/ci.json | 6 +-- .../examples/WiFiClientSecure/ci.json | 6 +-- .../WiFiClientSecureEnterprise/ci.json | 6 +-- .../WiFiClientSecureProtocolUpgrade/ci.json | 6 +-- .../WiFiClientShowPeerCredentials/ci.json | 6 +-- .../WiFiClientTrustOnFirstUse/ci.json | 6 +-- .../examples/COAP/coap_lamp/ci.json | 11 ++-- .../examples/COAP/coap_switch/ci.json | 11 ++-- .../OpenThread/examples/SimpleCLI/ci.json | 11 ++-- .../OpenThread/examples/SimpleNode/ci.json | 11 ++-- .../ExtendedRouterNode/ci.json | 11 ++-- .../SimpleThreadNetwork/LeaderNode/ci.json | 11 ++-- .../SimpleThreadNetwork/RouterNode/ci.json | 11 ++-- .../OpenThread/examples/ThreadScan/ci.json | 11 ++-- .../OpenThread/examples/onReceive/ci.json | 11 ++-- libraries/PPP/examples/PPP_Basic/ci.json | 5 ++ .../PPP/examples/PPP_WIFI_BRIDGE/ci.json | 7 +-- .../RainMaker/examples/RMakerCustom/ci.json | 7 +-- .../examples/RMakerCustomAirCooler/ci.json | 7 +-- .../examples/RMakerSonoffDualR3/ci.json | 7 +-- .../RainMaker/examples/RMakerSwitch/ci.json | 7 +-- libraries/SD/examples/SD_time/ci.json | 6 +-- libraries/SD_MMC/examples/SD2USBMSC/ci.json | 11 ++-- libraries/SD_MMC/examples/SDMMC_Test/ci.json | 9 ++-- libraries/SD_MMC/examples/SDMMC_time/ci.json | 10 ++-- .../SPI_Multiple_Buses/SPI_Multiple_Buses.ino | 2 +- .../SPI/examples/SPI_Multiple_Buses/ci.json | 8 ++- libraries/SPIFFS/examples/SPIFFS_time/ci.json | 6 +-- .../examples/SimpleBleDevice/ci.json | 8 +-- .../USB/examples/CompositeDevice/ci.json | 9 ++-- .../USB/examples/ConsumerControl/ci.json | 9 ++-- .../USB/examples/CustomHIDDevice/ci.json | 9 ++-- libraries/USB/examples/FirmwareMSC/ci.json | 9 ++-- libraries/USB/examples/Gamepad/ci.json | 9 ++-- libraries/USB/examples/HIDVendor/ci.json | 9 ++-- .../examples/Keyboard/KeyboardLogout/ci.json | 9 ++-- .../examples/Keyboard/KeyboardMessage/ci.json | 9 ++-- .../Keyboard/KeyboardReprogram/ci.json | 9 ++-- .../examples/Keyboard/KeyboardSerial/ci.json | 9 ++-- .../examples/KeyboardAndMouseControl/ci.json | 9 ++-- .../USB/examples/MIDI/MidiController/ci.json | 9 ++-- .../USB/examples/MIDI/MidiInterface/ci.json | 9 ++-- .../USB/examples/MIDI/MidiMusicBox/ci.json | 9 ++-- .../USB/examples/MIDI/ReceiveMidi/ci.json | 9 ++-- .../examples/Mouse/ButtonMouseControl/ci.json | 9 ++-- libraries/USB/examples/SystemControl/ci.json | 9 ++-- libraries/USB/examples/USBMSC/ci.json | 9 ++-- libraries/USB/examples/USBSerial/ci.json | 9 ++-- libraries/USB/examples/USBVendor/ci.json | 9 ++-- .../Update/examples/AWS_S3_OTA_Update/ci.json | 6 +-- .../Update/examples/HTTPS_OTA_Update/ci.json | 6 +-- .../HTTP_Client_AES_OTA_Update/ci.json | 6 +-- .../HTTP_Server_AES_OTA_Update/ci.json | 6 +-- .../Update/examples/OTAWebUpdater/ci.json | 6 +-- .../examples/AdvancedWebServer/ci.json | 6 +-- .../WebServer/examples/FSBrowser/ci.json | 6 +-- libraries/WebServer/examples/Filters/ci.json | 6 +-- .../WebServer/examples/HelloServer/ci.json | 6 +-- .../examples/HttpAdvancedAuth/ci.json | 6 +-- .../examples/HttpAuthCallback/ci.json | 6 +-- .../examples/HttpAuthCallbackInline/ci.json | 6 +-- .../WebServer/examples/HttpBasicAuth/ci.json | 6 +-- .../examples/HttpBasicAuthSHA1/ci.json | 6 +-- .../HttpBasicAuthSHA1orBearerToken/ci.json | 6 +-- .../examples/MultiHomedServers/ci.json | 6 +-- .../WebServer/examples/PathArgServer/ci.json | 6 +-- .../WebServer/examples/SDWebServer/ci.json | 6 +-- .../examples/SimpleAuthentification/ci.json | 6 +-- .../WebServer/examples/UploadHugeFile/ci.json | 6 +-- .../WebServer/examples/WebServer/ci.json | 6 +-- .../WebServer/examples/WebUpdate/ci.json | 6 +-- .../WiFi/examples/FTM/FTM_Initiator/ci.json | 6 +-- .../WiFi/examples/FTM/FTM_Responder/ci.json | 6 +-- .../WiFi/examples/SimpleWiFiServer/ci.json | 6 +-- libraries/WiFi/examples/WPS/ci.json | 6 +-- .../WiFi/examples/WiFiAccessPoint/ci.json | 6 +-- .../WiFi/examples/WiFiBlueToothSwitch/ci.json | 4 +- libraries/WiFi/examples/WiFiClient/ci.json | 6 +-- .../WiFi/examples/WiFiClientBasic/ci.json | 6 +-- .../WiFi/examples/WiFiClientConnect/ci.json | 6 +-- .../examples/WiFiClientEnterprise/ci.json | 6 +-- .../WiFi/examples/WiFiClientEvents/ci.json | 6 +-- .../WiFi/examples/WiFiClientStaticIP/ci.json | 6 +-- libraries/WiFi/examples/WiFiExtender/ci.json | 6 +-- libraries/WiFi/examples/WiFiIPv6/ci.json | 6 +-- libraries/WiFi/examples/WiFiMulti/ci.json | 6 +-- .../WiFi/examples/WiFiMultiAdvanced/ci.json | 6 +-- libraries/WiFi/examples/WiFiScan/ci.json | 6 +-- libraries/WiFi/examples/WiFiScanAsync/ci.json | 6 +-- .../WiFi/examples/WiFiScanDualAntenna/ci.json | 6 +-- libraries/WiFi/examples/WiFiScanTime/ci.json | 6 +-- .../WiFi/examples/WiFiSmartConfig/ci.json | 6 +-- .../WiFi/examples/WiFiTelnetToSerial/ci.json | 6 +-- libraries/WiFi/examples/WiFiUDPClient/ci.json | 6 +-- libraries/WiFiProv/examples/WiFiProv/ci.json | 6 +-- libraries/Wire/examples/WireMaster/ci.json | 5 ++ libraries/Wire/examples/WireScan/ci.json | 5 ++ libraries/Wire/examples/WireSlave/ci.json | 6 +-- tests/validation/democfg/ci.json | 3 ++ tests/validation/touch/ci.json | 8 ++- tests/validation/wifi/ci.json | 6 +-- 169 files changed, 654 insertions(+), 688 deletions(-) create mode 100644 libraries/ESP_I2S/examples/ES8388_loopback/ci.json create mode 100644 libraries/ESP_I2S/examples/Simple_tone/ci.json create mode 100644 libraries/PPP/examples/PPP_Basic/ci.json create mode 100644 libraries/Wire/examples/WireMaster/ci.json create mode 100644 libraries/Wire/examples/WireScan/ci.json diff --git a/.github/scripts/install-platformio-esp32.sh b/.github/scripts/install-platformio-esp32.sh index a92e1103770..393c9f3a7d6 100755 --- a/.github/scripts/install-platformio-esp32.sh +++ b/.github/scripts/install-platformio-esp32.sh @@ -6,6 +6,7 @@ PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git" TOOLCHAIN_VERSION="12.2.0+20230208" ESPTOOLPY_VERSION="~1.40501.0" ESPRESSIF_ORGANIZATION_NAME="espressif" +LIBS_DIR="tools/esp32-arduino-libs" echo "Installing Python Wheel ..." pip install wheel > /dev/null 2>&1 @@ -88,12 +89,25 @@ function count_sketches(){ # count_sketches local sketchname=$(basename $sketch) if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then continue + elif [ -f $sketchdir/ci.json ]; then + # If the target is listed as false, skip the sketch. Otherwise, include it. + is_target=$(jq -r '.targets[esp32]' $sketchdir/ci.json) + if [[ "$is_target" == "false" ]]; then + continue + fi + + # Check if the sketch requires any configuration options + requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) + if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + for requirement in $requirements; do + found_line=$(grep -E "^$requirement" $LIBS_DIR/esp32/sdkconfig) + if [[ "$found_line" == "" ]]; then + continue 2 + fi + done + fi fi - is_target=$(jq -r --arg target $target '.targets[$target]' $sketchdir/ci.json) - # If the target is listed as false, skip the sketch. Otherwise, include it. - if [[ "$is_target" == "false" ]]; then - continue - fi + echo $sketch >> sketches.txt sketchnum=$(($sketchnum + 1)) done @@ -163,12 +177,27 @@ function build_pio_sketches(){ # build_pio_sketches [extra-options] while [ ! -z "$1" ]; do case "$1" in @@ -140,16 +142,25 @@ function build_sketch(){ # build_sketch [ex sketchname=$(basename $sketchdir) - # If the target is listed as false, skip the sketch. Otherwise, include it. if [ -f $sketchdir/ci.json ]; then + # If the target is listed as false, skip the sketch. Otherwise, include it. is_target=$(jq -r --arg target $target '.targets[$target]' $sketchdir/ci.json) - else - is_target="true" - fi + if [[ "$is_target" == "false" ]]; then + echo "Skipping $sketchname for target $target" + exit 0 + fi - if [[ "$is_target" == "false" ]]; then - echo "Skipping $sketchname for target $target" - exit 0 + # Check if the sketch requires any configuration options + requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) + if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + for requirement in $requirements; do + found_line=$(grep -E "^$requirement" $LIBS_DIR/$target/sdkconfig) + if [[ "$found_line" == "" ]]; then + echo "Target $target does not meet the requirement $requirement for $sketchname. Skipping." + exit 0 + fi + done + fi fi ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp" @@ -288,16 +299,23 @@ function count_sketches(){ # count_sketches [target] [file] local sketchname=$(basename $sketch) if [[ "$sketchdirname.ino" != "$sketchname" ]]; then continue - elif [[ -n $target ]]; then + elif [[ -n $target ]] && [[ -f $sketchdir/ci.json ]]; then # If the target is listed as false, skip the sketch. Otherwise, include it. - if [ -f $sketchdir/ci.json ]; then - is_target=$(jq -r --arg target $target '.targets[$target]' $sketchdir/ci.json) - else - is_target="true" - fi + is_target=$(jq -r --arg target $target '.targets[$target]' $sketchdir/ci.json) if [[ "$is_target" == "false" ]]; then continue fi + + # Check if the sketch requires any configuration options + requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) + if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + for requirement in $requirements; do + found_line=$(grep -E "^$requirement" $LIBS_DIR/$target/sdkconfig) + if [[ "$found_line" == "" ]]; then + continue 2 + fi + done + fi fi echo $sketch >> sketches.txt sketchnum=$(($sketchnum + 1)) diff --git a/.github/scripts/tests_run.sh b/.github/scripts/tests_run.sh index d53d900e8fa..7f990bea45d 100755 --- a/.github/scripts/tests_run.sh +++ b/.github/scripts/tests_run.sh @@ -10,19 +10,29 @@ function run_test() { local result=0 local error=0 - # If the target or platform is listed as false, skip the sketch. Otherwise, include it. if [ -f $sketchdir/ci.json ]; then + # If the target or platform is listed as false, skip the sketch. Otherwise, include it. is_target=$(jq -r --arg target $target '.targets[$target]' $sketchdir/ci.json) selected_platform=$(jq -r --arg platform $platform '.platforms[$platform]' $sketchdir/ci.json) - else - is_target="true" - selected_platform="true" - fi - if [[ $is_target == "false" ]] || [[ $selected_platform == "false" ]]; then - printf "\033[93mSkipping $sketchname test for $target, platform: $platform\033[0m\n" - printf "\n\n\n" - return 0 + if [[ $is_target == "false" ]] || [[ $selected_platform == "false" ]]; then + printf "\033[93mSkipping $sketchname test for $target, platform: $platform\033[0m\n" + printf "\n\n\n" + return 0 + fi + + # Check if the sketch requires any configuration options + requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) + if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + for requirement in $requirements; do + found_line=$(grep -E "^$requirement" $LIBS_DIR/$target/sdkconfig) + if [[ "$found_line" == "" ]]; then + printf "\033[93mTarget $target does not meet the requirement $requirement for $sketchname. Skipping.\033[0m\n" + printf "\n\n\n" + return 0 + fi + done + fi fi if [ $options -eq 0 ] && [ -f $sketchdir/ci.json ]; then @@ -110,6 +120,7 @@ function run_test() { SCRIPTS_DIR="./.github/scripts" COUNT_SKETCHES="${SCRIPTS_DIR}/sketch_utils.sh count" +LIBS_DIR="tools/esp32-arduino-libs" platform="hardware" wokwi_timeout=60000 diff --git a/docs/en/contributing.rst b/docs/en/contributing.rst index acea254c3e3..26272f3d1c3 100644 --- a/docs/en/contributing.rst +++ b/docs/en/contributing.rst @@ -109,17 +109,44 @@ Also: Testing ******* -Be sure you have tested the example in all the supported targets. If the example works only with specific targets, -edit/add the ``ci.json`` in the same folder as the sketch to specify the supported targets. By default, -all targets are assumed to be supported. +Be sure you have tested the example in all the supported targets. If the example some specific hardware requirements, +edit/add the ``ci.json`` in the same folder as the sketch to specify the regular expression for the +required configurations from ``sdkconfig``. +This will ensure that the CI system will run the test only on the targets that have the required configurations. -Here is an example of the ``ci.json`` file where the example does not support ESP32-H2 and ESP32-S2: +You can check the available configurations in the ``sdkconfig`` file in the ``tools/esp32-arduino-libs/`` folder. + +Here is an example of the ``ci.json`` file where the example requires Wi-Fi to work properly: + +.. code-block:: json + + { + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] + } + +.. note:: + + The list of configurations will be checked against the ``sdkconfig`` file in the target folder. If the configuration is not present in the ``sdkconfig``, + the test will be skipped for that target. That means that the test will only run on the targets that have **ALL** the required configurations. + + Also, by default, the "match start of line" character (``^``) will be added to the beginning of each configuration. + That means that the configuration must be at the beginning of the line in the ``sdkconfig`` file. + +Sometimes, the example might not be supported by some target, even if the target has the required configurations +(like resources limitations or requiring a specific SoC). To avoid compilation errors, you can add the target to the ``ci.json`` +file so the CI system will force to skip the test on that target. + +Here is an example of the ``ci.json`` file where the example is requires Wi-Fi to work properly but is also not supported by the ESP32-S2 target: .. code-block:: json { + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ], "targets": { - "esp32h2": false, "esp32s2": false } } @@ -130,17 +157,17 @@ For example, in the sketch: .. code-block:: arduino /* - THIS FEATURE IS SUPPORTED ONLY BY ESP32-S2 AND ESP32-C3 + THIS FEATURE REQUIRES WI-FI SUPPORT AND IS NOT AVAILABLE FOR ESP32-S2 AS IT DOES NOT HAVE ENOUGH RAM. */ And in the ``README.md`` file: .. code-block:: markdown - Currently, this example supports the following targets. + Currently, this example requires Wi-Fi and supports the following targets. - | Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | - | ----------------- | ----- | -------- | -------- | -------- | + | Supported Targets | ESP32 | ESP32-H2 | ESP32-S3 | ESP32-C3 | ESP32-C6 | + | ----------------- | ----- | -------- | -------- | -------- | -------- | Example Template **************** @@ -341,8 +368,11 @@ CI JSON File The ``ci.json`` file is used to specify how the test suite and sketches will handled by the CI system. It can contain the following fields: -* ``targets``: A dictionary that specifies the supported targets. The key is the target name and the value is a boolean that specifies if the - target is supported. By default, all targets are assumed to be supported. This field is also valid for examples. +* ``requires``: A list of configurations in ``sdkconfig`` that are required to run the test suite. The test suite will only run on the targets + that have the required configurations. By default, no configurations are required. +* ``targets``: A dictionary that specifies the targets for which the tests will be run. The key is the target name and the value is a boolean + that specifies if the test should be run for that target. By default, all targets are enabled as long as they have the required configurations + specified in the ``requires`` field. This field is also valid for examples. * ``platforms``: A dictionary that specifies the supported platforms. The key is the platform name and the value is a boolean that specifies if the platform is supported. By default, all platforms are assumed to be supported. * ``extra_tags``: A list of extra tags that the runner will require when running the test suite in hardware. By default, no extra tags are required. diff --git a/libraries/ArduinoOTA/examples/BasicOTA/ci.json b/libraries/ArduinoOTA/examples/BasicOTA/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/ArduinoOTA/examples/BasicOTA/ci.json +++ b/libraries/ArduinoOTA/examples/BasicOTA/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/AsyncUDP/examples/AsyncUDPClient/ci.json b/libraries/AsyncUDP/examples/AsyncUDPClient/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/AsyncUDP/examples/AsyncUDPClient/ci.json +++ b/libraries/AsyncUDP/examples/AsyncUDPClient/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/ci.json b/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/ci.json +++ b/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/AsyncUDP/examples/AsyncUDPServer/ci.json b/libraries/AsyncUDP/examples/AsyncUDPServer/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/AsyncUDP/examples/AsyncUDPServer/ci.json +++ b/libraries/AsyncUDP/examples/AsyncUDPServer/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/BLE5_extended_scan/ci.json b/libraries/BLE/examples/BLE5_extended_scan/ci.json index edef5051e09..9f7646a74a6 100644 --- a/libraries/BLE/examples/BLE5_extended_scan/ci.json +++ b/libraries/BLE/examples/BLE5_extended_scan/ci.json @@ -1,6 +1,5 @@ { - "targets": { - "esp32": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_50_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/BLE5_multi_advertising/ci.json b/libraries/BLE/examples/BLE5_multi_advertising/ci.json index edef5051e09..9f7646a74a6 100644 --- a/libraries/BLE/examples/BLE5_multi_advertising/ci.json +++ b/libraries/BLE/examples/BLE5_multi_advertising/ci.json @@ -1,6 +1,5 @@ { - "targets": { - "esp32": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_50_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json index edef5051e09..9f7646a74a6 100644 --- a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json +++ b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json @@ -1,6 +1,5 @@ { - "targets": { - "esp32": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_50_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/BLE5_periodic_sync/ci.json b/libraries/BLE/examples/BLE5_periodic_sync/ci.json index edef5051e09..9f7646a74a6 100644 --- a/libraries/BLE/examples/BLE5_periodic_sync/ci.json +++ b/libraries/BLE/examples/BLE5_periodic_sync/ci.json @@ -1,6 +1,5 @@ { - "targets": { - "esp32": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_50_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/Beacon_Scanner/ci.json b/libraries/BLE/examples/Beacon_Scanner/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/Beacon_Scanner/ci.json +++ b/libraries/BLE/examples/Beacon_Scanner/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/Client/ci.json b/libraries/BLE/examples/Client/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/Client/ci.json +++ b/libraries/BLE/examples/Client/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json b/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json index 521ae8f5ff1..c23553ec084 100644 --- a/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json +++ b/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json @@ -1,6 +1,5 @@ { - "targets": { - "esp32h2": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/EddystoneURL_Beacon/ci.json b/libraries/BLE/examples/EddystoneURL_Beacon/ci.json index 521ae8f5ff1..c23553ec084 100644 --- a/libraries/BLE/examples/EddystoneURL_Beacon/ci.json +++ b/libraries/BLE/examples/EddystoneURL_Beacon/ci.json @@ -1,6 +1,5 @@ { - "targets": { - "esp32h2": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/Notify/ci.json b/libraries/BLE/examples/Notify/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/Notify/ci.json +++ b/libraries/BLE/examples/Notify/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/Scan/ci.json b/libraries/BLE/examples/Scan/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/Scan/ci.json +++ b/libraries/BLE/examples/Scan/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/Server/ci.json b/libraries/BLE/examples/Server/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/Server/ci.json +++ b/libraries/BLE/examples/Server/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/Server_multiconnect/ci.json b/libraries/BLE/examples/Server_multiconnect/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/Server_multiconnect/ci.json +++ b/libraries/BLE/examples/Server_multiconnect/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/UART/ci.json b/libraries/BLE/examples/UART/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/UART/ci.json +++ b/libraries/BLE/examples/UART/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/Write/ci.json b/libraries/BLE/examples/Write/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/Write/ci.json +++ b/libraries/BLE/examples/Write/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BLE/examples/iBeacon/ci.json b/libraries/BLE/examples/iBeacon/ci.json index 1443137ab0d..c23553ec084 100644 --- a/libraries/BLE/examples/iBeacon/ci.json +++ b/libraries/BLE/examples/iBeacon/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_BLE_SUPPORTED=y" + ] } diff --git a/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json b/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json index 1af543242e3..98fda4381b1 100644 --- a/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json +++ b/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_BT_SPP_ENABLED=y" + ] } diff --git a/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json b/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json index 1af543242e3..98fda4381b1 100644 --- a/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json +++ b/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_BT_SPP_ENABLED=y" + ] } diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json index 1af543242e3..98fda4381b1 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_BT_SPP_ENABLED=y" + ] } diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json index 1af543242e3..98fda4381b1 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_BT_SPP_ENABLED=y" + ] } diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json index 1af543242e3..98fda4381b1 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_BT_SPP_ENABLED=y" + ] } diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json index 1af543242e3..98fda4381b1 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_BT_SPP_ENABLED=y" + ] } diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json index 1af543242e3..98fda4381b1 100644 --- a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json +++ b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_BT_SPP_ENABLED=y" + ] } diff --git a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json index 1af543242e3..98fda4381b1 100644 --- a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json +++ b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_BT_SPP_ENABLED=y" + ] } diff --git a/libraries/DNSServer/examples/CaptivePortal/ci.json b/libraries/DNSServer/examples/CaptivePortal/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/DNSServer/examples/CaptivePortal/ci.json +++ b/libraries/DNSServer/examples/CaptivePortal/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/ci.json b/libraries/ESP32/examples/Camera/CameraWebServer/ci.json index 25c42144223..7e0f3c89986 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/ci.json +++ b/libraries/ESP32/examples/Camera/CameraWebServer/ci.json @@ -1,7 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_CAMERA_TASK_STACK_SIZE=[0-9]+" + ] } diff --git a/libraries/ESP32/examples/HWCDC_Events/ci.json b/libraries/ESP32/examples/HWCDC_Events/ci.json index d6c4351c868..56e38bbcdf2 100644 --- a/libraries/ESP32/examples/HWCDC_Events/ci.json +++ b/libraries/ESP32/examples/HWCDC_Events/ci.json @@ -4,8 +4,7 @@ "espressif:esp32:esp32s3:USBMode=hwcdc,PartitionScheme=huge_app,FlashMode=dio" ] }, - "targets": { - "esp32": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y" + ] } diff --git a/libraries/ESP32/examples/Time/SimpleTime/ci.json b/libraries/ESP32/examples/Time/SimpleTime/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/ESP32/examples/Time/SimpleTime/ci.json +++ b/libraries/ESP32/examples/Time/SimpleTime/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/ESP32/examples/Touch/TouchButton/ci.json b/libraries/ESP32/examples/Touch/TouchButton/ci.json index 1af543242e3..cec76a84f9d 100644 --- a/libraries/ESP32/examples/Touch/TouchButton/ci.json +++ b/libraries/ESP32/examples/Touch/TouchButton/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_SOC_TOUCH_VERSION_1=y" + ] } diff --git a/libraries/ESP32/examples/Touch/TouchButtonV2/ci.json b/libraries/ESP32/examples/Touch/TouchButtonV2/ci.json index e7d65393dd6..2710fa7940e 100644 --- a/libraries/ESP32/examples/Touch/TouchButtonV2/ci.json +++ b/libraries/ESP32/examples/Touch/TouchButtonV2/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_TOUCH_VERSION_2=y" + ] } diff --git a/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json b/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json index 25c42144223..c0ecf9fc0a5 100644 --- a/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json +++ b/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json @@ -1,7 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y" + ] } diff --git a/libraries/ESP32/examples/Touch/TouchRead/ci.json b/libraries/ESP32/examples/Touch/TouchRead/ci.json index 25c42144223..c0ecf9fc0a5 100644 --- a/libraries/ESP32/examples/Touch/TouchRead/ci.json +++ b/libraries/ESP32/examples/Touch/TouchRead/ci.json @@ -1,7 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y" + ] } diff --git a/libraries/ESP_I2S/examples/ES8388_loopback/ci.json b/libraries/ESP_I2S/examples/ES8388_loopback/ci.json new file mode 100644 index 00000000000..e0f64e28943 --- /dev/null +++ b/libraries/ESP_I2S/examples/ES8388_loopback/ci.json @@ -0,0 +1,6 @@ +{ + "requires": [ + "CONFIG_SOC_I2S_SUPPORTED=y", + "CONFIG_SOC_I2C_SUPPORTED=y" + ] +} diff --git a/libraries/ESP_I2S/examples/Record_to_WAV/ci.json b/libraries/ESP_I2S/examples/Record_to_WAV/ci.json index 35b6e255471..a45dc2f0120 100644 --- a/libraries/ESP_I2S/examples/Record_to_WAV/ci.json +++ b/libraries/ESP_I2S/examples/Record_to_WAV/ci.json @@ -1,8 +1,6 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_SDMMC_HOST_SUPPORTED=y", + "CONFIG_SOC_I2S_SUPPORTED=y" + ] } diff --git a/libraries/ESP_I2S/examples/Simple_tone/ci.json b/libraries/ESP_I2S/examples/Simple_tone/ci.json new file mode 100644 index 00000000000..9842f2f9b2a --- /dev/null +++ b/libraries/ESP_I2S/examples/Simple_tone/ci.json @@ -0,0 +1,5 @@ +{ + "requires": [ + "CONFIG_SOC_I2S_SUPPORTED=y" + ] +} diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/ESP_SR/examples/Basic/ci.json b/libraries/ESP_SR/examples/Basic/ci.json index dca52699ab3..c9b0955f8f2 100644 --- a/libraries/ESP_SR/examples/Basic/ci.json +++ b/libraries/ESP_SR/examples/Basic/ci.json @@ -4,6 +4,9 @@ "espressif:esp32:esp32s3:USBMode=default,PartitionScheme=esp_sr_16,FlashSize=16M,FlashMode=dio" ] }, + "requires": [ + "CONFIG_SOC_I2S_SUPPORTED=y" + ], "targets": { "esp32": false, "esp32c3": false, diff --git a/libraries/ESPmDNS/examples/mDNS-SD_Extended/ci.json b/libraries/ESPmDNS/examples/mDNS-SD_Extended/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/ESPmDNS/examples/mDNS-SD_Extended/ci.json +++ b/libraries/ESPmDNS/examples/mDNS-SD_Extended/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/ESPmDNS/examples/mDNS_Web_Server/ci.json b/libraries/ESPmDNS/examples/mDNS_Web_Server/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/ESPmDNS/examples/mDNS_Web_Server/ci.json +++ b/libraries/ESPmDNS/examples/mDNS_Web_Server/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/Ethernet/examples/ETH_LAN8720/ci.json b/libraries/Ethernet/examples/ETH_LAN8720/ci.json index 1af543242e3..dcdfd06db51 100644 --- a/libraries/Ethernet/examples/ETH_LAN8720/ci.json +++ b/libraries/Ethernet/examples/ETH_LAN8720/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_ETH_USE_ESP32_EMAC=y" + ] } diff --git a/libraries/Ethernet/examples/ETH_TLK110/ci.json b/libraries/Ethernet/examples/ETH_TLK110/ci.json index 1af543242e3..dcdfd06db51 100644 --- a/libraries/Ethernet/examples/ETH_TLK110/ci.json +++ b/libraries/Ethernet/examples/ETH_TLK110/ci.json @@ -1,9 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_ETH_USE_ESP32_EMAC=y" + ] } diff --git a/libraries/Ethernet/examples/ETH_WIFI_BRIDGE/ci.json b/libraries/Ethernet/examples/ETH_WIFI_BRIDGE/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/Ethernet/examples/ETH_WIFI_BRIDGE/ci.json +++ b/libraries/Ethernet/examples/ETH_WIFI_BRIDGE/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/FFat/examples/FFat_time/ci.json b/libraries/FFat/examples/FFat_time/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/FFat/examples/FFat_time/ci.json +++ b/libraries/FFat/examples/FFat_time/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPClient/examples/Authorization/ci.json b/libraries/HTTPClient/examples/Authorization/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPClient/examples/Authorization/ci.json +++ b/libraries/HTTPClient/examples/Authorization/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPClient/examples/BasicHttpClient/ci.json b/libraries/HTTPClient/examples/BasicHttpClient/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPClient/examples/BasicHttpClient/ci.json +++ b/libraries/HTTPClient/examples/BasicHttpClient/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPClient/examples/BasicHttpsClient/ci.json b/libraries/HTTPClient/examples/BasicHttpsClient/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPClient/examples/BasicHttpsClient/ci.json +++ b/libraries/HTTPClient/examples/BasicHttpsClient/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json +++ b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPClient/examples/ReuseConnection/ci.json b/libraries/HTTPClient/examples/ReuseConnection/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPClient/examples/ReuseConnection/ci.json +++ b/libraries/HTTPClient/examples/ReuseConnection/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPClient/examples/StreamHttpClient/ci.json b/libraries/HTTPClient/examples/StreamHttpClient/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPClient/examples/StreamHttpClient/ci.json +++ b/libraries/HTTPClient/examples/StreamHttpClient/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPUpdate/examples/httpUpdate/ci.json b/libraries/HTTPUpdate/examples/httpUpdate/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPUpdate/examples/httpUpdate/ci.json +++ b/libraries/HTTPUpdate/examples/httpUpdate/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/ci.json b/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/ci.json +++ b/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json +++ b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/HTTPUpdateServer/examples/WebUpdater/ci.json b/libraries/HTTPUpdateServer/examples/WebUpdater/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/HTTPUpdateServer/examples/WebUpdater/ci.json +++ b/libraries/HTTPUpdateServer/examples/WebUpdater/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/Insights/examples/DiagnosticsSmokeTest/ci.json b/libraries/Insights/examples/DiagnosticsSmokeTest/ci.json index 90f5ecfe4d2..fd3a9295b01 100644 --- a/libraries/Insights/examples/DiagnosticsSmokeTest/ci.json +++ b/libraries/Insights/examples/DiagnosticsSmokeTest/ci.json @@ -1,6 +1,6 @@ { - "targets": { - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_ESP_INSIGHTS_ENABLED=y", + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/Insights/examples/MinimalDiagnostics/ci.json b/libraries/Insights/examples/MinimalDiagnostics/ci.json index 90f5ecfe4d2..fd3a9295b01 100644 --- a/libraries/Insights/examples/MinimalDiagnostics/ci.json +++ b/libraries/Insights/examples/MinimalDiagnostics/ci.json @@ -1,6 +1,6 @@ { - "targets": { - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_ESP_INSIGHTS_ENABLED=y", + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/LittleFS/examples/LITTLEFS_time/ci.json b/libraries/LittleFS/examples/LITTLEFS_time/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/LittleFS/examples/LITTLEFS_time/ci.json +++ b/libraries/LittleFS/examples/LITTLEFS_time/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/NetBIOS/examples/ESP_NBNST/ci.json b/libraries/NetBIOS/examples/ESP_NBNST/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/NetBIOS/examples/ESP_NBNST/ci.json +++ b/libraries/NetBIOS/examples/ESP_NBNST/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientInsecure/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientInsecure/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientInsecure/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientInsecure/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientPSK/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientPSK/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientPSK/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientPSK/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureProtocolUpgrade/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecureProtocolUpgrade/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecureProtocolUpgrade/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureProtocolUpgrade/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientShowPeerCredentials/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientShowPeerCredentials/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientShowPeerCredentials/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientShowPeerCredentials/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/NetworkClientSecure/examples/WiFiClientTrustOnFirstUse/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientTrustOnFirstUse/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientTrustOnFirstUse/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientTrustOnFirstUse/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/COAP/coap_lamp/ci.json b/libraries/OpenThread/examples/COAP/coap_lamp/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/COAP/coap_lamp/ci.json +++ b/libraries/OpenThread/examples/COAP/coap_lamp/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/COAP/coap_switch/ci.json b/libraries/OpenThread/examples/COAP/coap_switch/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/COAP/coap_switch/ci.json +++ b/libraries/OpenThread/examples/COAP/coap_switch/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/SimpleCLI/ci.json b/libraries/OpenThread/examples/SimpleCLI/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/SimpleCLI/ci.json +++ b/libraries/OpenThread/examples/SimpleCLI/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/SimpleNode/ci.json b/libraries/OpenThread/examples/SimpleNode/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/SimpleNode/ci.json +++ b/libraries/OpenThread/examples/SimpleNode/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json b/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json +++ b/libraries/OpenThread/examples/SimpleThreadNetwork/ExtendedRouterNode/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/SimpleThreadNetwork/LeaderNode/ci.json b/libraries/OpenThread/examples/SimpleThreadNetwork/LeaderNode/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/SimpleThreadNetwork/LeaderNode/ci.json +++ b/libraries/OpenThread/examples/SimpleThreadNetwork/LeaderNode/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/SimpleThreadNetwork/RouterNode/ci.json b/libraries/OpenThread/examples/SimpleThreadNetwork/RouterNode/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/SimpleThreadNetwork/RouterNode/ci.json +++ b/libraries/OpenThread/examples/SimpleThreadNetwork/RouterNode/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/ThreadScan/ci.json b/libraries/OpenThread/examples/ThreadScan/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/ThreadScan/ci.json +++ b/libraries/OpenThread/examples/ThreadScan/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/OpenThread/examples/onReceive/ci.json b/libraries/OpenThread/examples/onReceive/ci.json index c60d9179992..2ee6af3490e 100644 --- a/libraries/OpenThread/examples/onReceive/ci.json +++ b/libraries/OpenThread/examples/onReceive/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c2": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "requires": [ + "CONFIG_OPENTHREAD_ENABLED=y", + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/PPP/examples/PPP_Basic/ci.json b/libraries/PPP/examples/PPP_Basic/ci.json new file mode 100644 index 00000000000..314587edcf6 --- /dev/null +++ b/libraries/PPP/examples/PPP_Basic/ci.json @@ -0,0 +1,5 @@ +{ + "requires": [ + "CONFIG_LWIP_PPP_SUPPORT=y" + ] +} diff --git a/libraries/PPP/examples/PPP_WIFI_BRIDGE/ci.json b/libraries/PPP/examples/PPP_WIFI_BRIDGE/ci.json index d8b3664bc65..513ab9a296a 100644 --- a/libraries/PPP/examples/PPP_WIFI_BRIDGE/ci.json +++ b/libraries/PPP/examples/PPP_WIFI_BRIDGE/ci.json @@ -1,5 +1,6 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_LWIP_PPP_SUPPORT=y", + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/RainMaker/examples/RMakerCustom/ci.json b/libraries/RainMaker/examples/RMakerCustom/ci.json index d8b3664bc65..de4e92436d7 100644 --- a/libraries/RainMaker/examples/RMakerCustom/ci.json +++ b/libraries/RainMaker/examples/RMakerCustom/ci.json @@ -1,5 +1,6 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK" + ] } diff --git a/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json b/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json index d8b3664bc65..de4e92436d7 100644 --- a/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json +++ b/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json @@ -1,5 +1,6 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK" + ] } diff --git a/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json b/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json index d8b3664bc65..de4e92436d7 100644 --- a/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json +++ b/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json @@ -1,5 +1,6 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK" + ] } diff --git a/libraries/RainMaker/examples/RMakerSwitch/ci.json b/libraries/RainMaker/examples/RMakerSwitch/ci.json index d8b3664bc65..de4e92436d7 100644 --- a/libraries/RainMaker/examples/RMakerSwitch/ci.json +++ b/libraries/RainMaker/examples/RMakerSwitch/ci.json @@ -1,5 +1,6 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK" + ] } diff --git a/libraries/SD/examples/SD_time/ci.json b/libraries/SD/examples/SD_time/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/SD/examples/SD_time/ci.json +++ b/libraries/SD/examples/SD_time/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/SD_MMC/examples/SD2USBMSC/ci.json b/libraries/SD_MMC/examples/SD2USBMSC/ci.json index 97ae5ee5616..125eed2e476 100644 --- a/libraries/SD_MMC/examples/SD2USBMSC/ci.json +++ b/libraries/SD_MMC/examples/SD2USBMSC/ci.json @@ -1,9 +1,6 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_SDMMC_HOST_SUPPORTED=y", + "CONFIG_TINYUSB_MSC_ENABLED=y" + ] } diff --git a/libraries/SD_MMC/examples/SDMMC_Test/ci.json b/libraries/SD_MMC/examples/SDMMC_Test/ci.json index 35b6e255471..a5221dae538 100644 --- a/libraries/SD_MMC/examples/SDMMC_Test/ci.json +++ b/libraries/SD_MMC/examples/SDMMC_Test/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_SDMMC_HOST_SUPPORTED=y" + ] } diff --git a/libraries/SD_MMC/examples/SDMMC_time/ci.json b/libraries/SD_MMC/examples/SDMMC_time/ci.json index 35b6e255471..bd4aac1d647 100644 --- a/libraries/SD_MMC/examples/SDMMC_time/ci.json +++ b/libraries/SD_MMC/examples/SDMMC_time/ci.json @@ -1,8 +1,6 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_SOC_SDMMC_HOST_SUPPORTED=y" + ] } diff --git a/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino b/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino index c73f6078c03..06765c64fd2 100644 --- a/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino +++ b/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino @@ -39,7 +39,7 @@ #define HSPI_SS 15 #endif -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if !defined(CONFIG_IDF_TARGET_ESP32) #define VSPI FSPI #endif diff --git a/libraries/SPI/examples/SPI_Multiple_Buses/ci.json b/libraries/SPI/examples/SPI_Multiple_Buses/ci.json index 25c42144223..cd27a02724b 100644 --- a/libraries/SPI/examples/SPI_Multiple_Buses/ci.json +++ b/libraries/SPI/examples/SPI_Multiple_Buses/ci.json @@ -1,7 +1,5 @@ { - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_SPI_PERIPH_NUM=[2-9]" + ] } diff --git a/libraries/SPIFFS/examples/SPIFFS_time/ci.json b/libraries/SPIFFS/examples/SPIFFS_time/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/SPIFFS/examples/SPIFFS_time/ci.json +++ b/libraries/SPIFFS/examples/SPIFFS_time/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/SimpleBLE/examples/SimpleBleDevice/ci.json b/libraries/SimpleBLE/examples/SimpleBleDevice/ci.json index a571a89a877..d33a23f332e 100644 --- a/libraries/SimpleBLE/examples/SimpleBleDevice/ci.json +++ b/libraries/SimpleBLE/examples/SimpleBleDevice/ci.json @@ -1,6 +1,6 @@ { - "targets": { - "esp32c3": false, - "esp32s2": false - } + "requires": [ + "CONFIG_BT_ENABLED=y", + "CONFIG_BLUEDROID_ENABLED=y" + ] } diff --git a/libraries/USB/examples/CompositeDevice/ci.json b/libraries/USB/examples/CompositeDevice/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/CompositeDevice/ci.json +++ b/libraries/USB/examples/CompositeDevice/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/ConsumerControl/ci.json b/libraries/USB/examples/ConsumerControl/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/ConsumerControl/ci.json +++ b/libraries/USB/examples/ConsumerControl/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/CustomHIDDevice/ci.json b/libraries/USB/examples/CustomHIDDevice/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/CustomHIDDevice/ci.json +++ b/libraries/USB/examples/CustomHIDDevice/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/FirmwareMSC/ci.json b/libraries/USB/examples/FirmwareMSC/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/FirmwareMSC/ci.json +++ b/libraries/USB/examples/FirmwareMSC/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/Gamepad/ci.json b/libraries/USB/examples/Gamepad/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/Gamepad/ci.json +++ b/libraries/USB/examples/Gamepad/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/HIDVendor/ci.json b/libraries/USB/examples/HIDVendor/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/HIDVendor/ci.json +++ b/libraries/USB/examples/HIDVendor/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/Keyboard/KeyboardLogout/ci.json b/libraries/USB/examples/Keyboard/KeyboardLogout/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/Keyboard/KeyboardLogout/ci.json +++ b/libraries/USB/examples/Keyboard/KeyboardLogout/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/Keyboard/KeyboardMessage/ci.json b/libraries/USB/examples/Keyboard/KeyboardMessage/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/Keyboard/KeyboardMessage/ci.json +++ b/libraries/USB/examples/Keyboard/KeyboardMessage/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/Keyboard/KeyboardReprogram/ci.json b/libraries/USB/examples/Keyboard/KeyboardReprogram/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/Keyboard/KeyboardReprogram/ci.json +++ b/libraries/USB/examples/Keyboard/KeyboardReprogram/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/Keyboard/KeyboardSerial/ci.json b/libraries/USB/examples/Keyboard/KeyboardSerial/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/Keyboard/KeyboardSerial/ci.json +++ b/libraries/USB/examples/Keyboard/KeyboardSerial/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/KeyboardAndMouseControl/ci.json b/libraries/USB/examples/KeyboardAndMouseControl/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/KeyboardAndMouseControl/ci.json +++ b/libraries/USB/examples/KeyboardAndMouseControl/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/MIDI/MidiController/ci.json b/libraries/USB/examples/MIDI/MidiController/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/MIDI/MidiController/ci.json +++ b/libraries/USB/examples/MIDI/MidiController/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/MIDI/MidiInterface/ci.json b/libraries/USB/examples/MIDI/MidiInterface/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/MIDI/MidiInterface/ci.json +++ b/libraries/USB/examples/MIDI/MidiInterface/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/MIDI/MidiMusicBox/ci.json b/libraries/USB/examples/MIDI/MidiMusicBox/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/MIDI/MidiMusicBox/ci.json +++ b/libraries/USB/examples/MIDI/MidiMusicBox/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/MIDI/ReceiveMidi/ci.json b/libraries/USB/examples/MIDI/ReceiveMidi/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/MIDI/ReceiveMidi/ci.json +++ b/libraries/USB/examples/MIDI/ReceiveMidi/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/Mouse/ButtonMouseControl/ci.json b/libraries/USB/examples/Mouse/ButtonMouseControl/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/Mouse/ButtonMouseControl/ci.json +++ b/libraries/USB/examples/Mouse/ButtonMouseControl/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/SystemControl/ci.json b/libraries/USB/examples/SystemControl/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/SystemControl/ci.json +++ b/libraries/USB/examples/SystemControl/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/USBMSC/ci.json b/libraries/USB/examples/USBMSC/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/USBMSC/ci.json +++ b/libraries/USB/examples/USBMSC/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/USBSerial/ci.json b/libraries/USB/examples/USBSerial/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/USBSerial/ci.json +++ b/libraries/USB/examples/USBSerial/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/USB/examples/USBVendor/ci.json b/libraries/USB/examples/USBVendor/ci.json index e7d65393dd6..f9ac7d0bec9 100644 --- a/libraries/USB/examples/USBVendor/ci.json +++ b/libraries/USB/examples/USBVendor/ci.json @@ -1,8 +1,5 @@ { - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_USB_OTG_SUPPORTED=y" + ] } diff --git a/libraries/Update/examples/AWS_S3_OTA_Update/ci.json b/libraries/Update/examples/AWS_S3_OTA_Update/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/Update/examples/AWS_S3_OTA_Update/ci.json +++ b/libraries/Update/examples/AWS_S3_OTA_Update/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/Update/examples/HTTPS_OTA_Update/ci.json b/libraries/Update/examples/HTTPS_OTA_Update/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/Update/examples/HTTPS_OTA_Update/ci.json +++ b/libraries/Update/examples/HTTPS_OTA_Update/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/Update/examples/HTTP_Client_AES_OTA_Update/ci.json b/libraries/Update/examples/HTTP_Client_AES_OTA_Update/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/Update/examples/HTTP_Client_AES_OTA_Update/ci.json +++ b/libraries/Update/examples/HTTP_Client_AES_OTA_Update/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/Update/examples/HTTP_Server_AES_OTA_Update/ci.json b/libraries/Update/examples/HTTP_Server_AES_OTA_Update/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/Update/examples/HTTP_Server_AES_OTA_Update/ci.json +++ b/libraries/Update/examples/HTTP_Server_AES_OTA_Update/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/Update/examples/OTAWebUpdater/ci.json b/libraries/Update/examples/OTAWebUpdater/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/Update/examples/OTAWebUpdater/ci.json +++ b/libraries/Update/examples/OTAWebUpdater/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/AdvancedWebServer/ci.json b/libraries/WebServer/examples/AdvancedWebServer/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/AdvancedWebServer/ci.json +++ b/libraries/WebServer/examples/AdvancedWebServer/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/FSBrowser/ci.json b/libraries/WebServer/examples/FSBrowser/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/FSBrowser/ci.json +++ b/libraries/WebServer/examples/FSBrowser/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/Filters/ci.json b/libraries/WebServer/examples/Filters/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/Filters/ci.json +++ b/libraries/WebServer/examples/Filters/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/HelloServer/ci.json b/libraries/WebServer/examples/HelloServer/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/HelloServer/ci.json +++ b/libraries/WebServer/examples/HelloServer/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/HttpAdvancedAuth/ci.json b/libraries/WebServer/examples/HttpAdvancedAuth/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/HttpAdvancedAuth/ci.json +++ b/libraries/WebServer/examples/HttpAdvancedAuth/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/HttpAuthCallback/ci.json b/libraries/WebServer/examples/HttpAuthCallback/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/HttpAuthCallback/ci.json +++ b/libraries/WebServer/examples/HttpAuthCallback/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/HttpAuthCallbackInline/ci.json b/libraries/WebServer/examples/HttpAuthCallbackInline/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/HttpAuthCallbackInline/ci.json +++ b/libraries/WebServer/examples/HttpAuthCallbackInline/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/HttpBasicAuth/ci.json b/libraries/WebServer/examples/HttpBasicAuth/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/HttpBasicAuth/ci.json +++ b/libraries/WebServer/examples/HttpBasicAuth/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/HttpBasicAuthSHA1/ci.json b/libraries/WebServer/examples/HttpBasicAuthSHA1/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/HttpBasicAuthSHA1/ci.json +++ b/libraries/WebServer/examples/HttpBasicAuthSHA1/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/ci.json b/libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/ci.json +++ b/libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/MultiHomedServers/ci.json b/libraries/WebServer/examples/MultiHomedServers/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/MultiHomedServers/ci.json +++ b/libraries/WebServer/examples/MultiHomedServers/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/PathArgServer/ci.json b/libraries/WebServer/examples/PathArgServer/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/PathArgServer/ci.json +++ b/libraries/WebServer/examples/PathArgServer/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/SDWebServer/ci.json b/libraries/WebServer/examples/SDWebServer/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/SDWebServer/ci.json +++ b/libraries/WebServer/examples/SDWebServer/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/SimpleAuthentification/ci.json b/libraries/WebServer/examples/SimpleAuthentification/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/SimpleAuthentification/ci.json +++ b/libraries/WebServer/examples/SimpleAuthentification/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/UploadHugeFile/ci.json b/libraries/WebServer/examples/UploadHugeFile/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/UploadHugeFile/ci.json +++ b/libraries/WebServer/examples/UploadHugeFile/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/WebServer/ci.json b/libraries/WebServer/examples/WebServer/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/WebServer/ci.json +++ b/libraries/WebServer/examples/WebServer/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WebServer/examples/WebUpdate/ci.json b/libraries/WebServer/examples/WebUpdate/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WebServer/examples/WebUpdate/ci.json +++ b/libraries/WebServer/examples/WebUpdate/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/FTM/FTM_Initiator/ci.json b/libraries/WiFi/examples/FTM/FTM_Initiator/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/FTM/FTM_Initiator/ci.json +++ b/libraries/WiFi/examples/FTM/FTM_Initiator/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/FTM/FTM_Responder/ci.json b/libraries/WiFi/examples/FTM/FTM_Responder/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/FTM/FTM_Responder/ci.json +++ b/libraries/WiFi/examples/FTM/FTM_Responder/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/SimpleWiFiServer/ci.json b/libraries/WiFi/examples/SimpleWiFiServer/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/SimpleWiFiServer/ci.json +++ b/libraries/WiFi/examples/SimpleWiFiServer/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WPS/ci.json b/libraries/WiFi/examples/WPS/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WPS/ci.json +++ b/libraries/WiFi/examples/WPS/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiAccessPoint/ci.json b/libraries/WiFi/examples/WiFiAccessPoint/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiAccessPoint/ci.json +++ b/libraries/WiFi/examples/WiFiAccessPoint/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiBlueToothSwitch/ci.json b/libraries/WiFi/examples/WiFiBlueToothSwitch/ci.json index 521ae8f5ff1..49a24f931bf 100644 --- a/libraries/WiFi/examples/WiFiBlueToothSwitch/ci.json +++ b/libraries/WiFi/examples/WiFiBlueToothSwitch/ci.json @@ -1,6 +1,8 @@ { + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ], "targets": { - "esp32h2": false, "esp32s2": false } } diff --git a/libraries/WiFi/examples/WiFiClient/ci.json b/libraries/WiFi/examples/WiFiClient/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiClient/ci.json +++ b/libraries/WiFi/examples/WiFiClient/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiClientBasic/ci.json b/libraries/WiFi/examples/WiFiClientBasic/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiClientBasic/ci.json +++ b/libraries/WiFi/examples/WiFiClientBasic/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiClientConnect/ci.json b/libraries/WiFi/examples/WiFiClientConnect/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiClientConnect/ci.json +++ b/libraries/WiFi/examples/WiFiClientConnect/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiClientEnterprise/ci.json b/libraries/WiFi/examples/WiFiClientEnterprise/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiClientEnterprise/ci.json +++ b/libraries/WiFi/examples/WiFiClientEnterprise/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiClientEvents/ci.json b/libraries/WiFi/examples/WiFiClientEvents/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiClientEvents/ci.json +++ b/libraries/WiFi/examples/WiFiClientEvents/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiClientStaticIP/ci.json b/libraries/WiFi/examples/WiFiClientStaticIP/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiClientStaticIP/ci.json +++ b/libraries/WiFi/examples/WiFiClientStaticIP/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiExtender/ci.json b/libraries/WiFi/examples/WiFiExtender/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiExtender/ci.json +++ b/libraries/WiFi/examples/WiFiExtender/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiIPv6/ci.json b/libraries/WiFi/examples/WiFiIPv6/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiIPv6/ci.json +++ b/libraries/WiFi/examples/WiFiIPv6/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiMulti/ci.json b/libraries/WiFi/examples/WiFiMulti/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiMulti/ci.json +++ b/libraries/WiFi/examples/WiFiMulti/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiMultiAdvanced/ci.json b/libraries/WiFi/examples/WiFiMultiAdvanced/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiMultiAdvanced/ci.json +++ b/libraries/WiFi/examples/WiFiMultiAdvanced/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiScan/ci.json b/libraries/WiFi/examples/WiFiScan/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiScan/ci.json +++ b/libraries/WiFi/examples/WiFiScan/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiScanAsync/ci.json b/libraries/WiFi/examples/WiFiScanAsync/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiScanAsync/ci.json +++ b/libraries/WiFi/examples/WiFiScanAsync/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiScanDualAntenna/ci.json b/libraries/WiFi/examples/WiFiScanDualAntenna/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiScanDualAntenna/ci.json +++ b/libraries/WiFi/examples/WiFiScanDualAntenna/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiScanTime/ci.json b/libraries/WiFi/examples/WiFiScanTime/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiScanTime/ci.json +++ b/libraries/WiFi/examples/WiFiScanTime/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiSmartConfig/ci.json b/libraries/WiFi/examples/WiFiSmartConfig/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiSmartConfig/ci.json +++ b/libraries/WiFi/examples/WiFiSmartConfig/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiTelnetToSerial/ci.json b/libraries/WiFi/examples/WiFiTelnetToSerial/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiTelnetToSerial/ci.json +++ b/libraries/WiFi/examples/WiFiTelnetToSerial/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFi/examples/WiFiUDPClient/ci.json b/libraries/WiFi/examples/WiFiUDPClient/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiUDPClient/ci.json +++ b/libraries/WiFi/examples/WiFiUDPClient/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/WiFiProv/examples/WiFiProv/ci.json b/libraries/WiFiProv/examples/WiFiProv/ci.json index d8b3664bc65..36babb82730 100644 --- a/libraries/WiFiProv/examples/WiFiProv/ci.json +++ b/libraries/WiFiProv/examples/WiFiProv/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } diff --git a/libraries/Wire/examples/WireMaster/ci.json b/libraries/Wire/examples/WireMaster/ci.json new file mode 100644 index 00000000000..1844adfc786 --- /dev/null +++ b/libraries/Wire/examples/WireMaster/ci.json @@ -0,0 +1,5 @@ +{ + "requires": [ + "CONFIG_SOC_I2C_SUPPORTED=y" + ] +} diff --git a/libraries/Wire/examples/WireScan/ci.json b/libraries/Wire/examples/WireScan/ci.json new file mode 100644 index 00000000000..1844adfc786 --- /dev/null +++ b/libraries/Wire/examples/WireScan/ci.json @@ -0,0 +1,5 @@ +{ + "requires": [ + "CONFIG_SOC_I2C_SUPPORTED=y" + ] +} diff --git a/libraries/Wire/examples/WireSlave/ci.json b/libraries/Wire/examples/WireSlave/ci.json index 46e0dfffebb..3c877975d62 100644 --- a/libraries/Wire/examples/WireSlave/ci.json +++ b/libraries/Wire/examples/WireSlave/ci.json @@ -1,5 +1,5 @@ { - "targets": { - "esp32c2": false - } + "requires": [ + "CONFIG_SOC_I2C_SUPPORT_SLAVE=y" + ] } diff --git a/tests/validation/democfg/ci.json b/tests/validation/democfg/ci.json index f74aa4e7eda..e4f275a4bca 100644 --- a/tests/validation/democfg/ci.json +++ b/tests/validation/democfg/ci.json @@ -16,6 +16,9 @@ "qemu": false, "wokwi": true }, + "requires": [ + "CONFIG_SOC_UART_SUPPORTED=y" + ], "targets": { "esp32": true, "esp32c3": true, diff --git a/tests/validation/touch/ci.json b/tests/validation/touch/ci.json index 8d58dbf5250..855e9bd964d 100644 --- a/tests/validation/touch/ci.json +++ b/tests/validation/touch/ci.json @@ -3,9 +3,7 @@ "qemu": false, "wokwi": false }, - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y" + ] } diff --git a/tests/validation/wifi/ci.json b/tests/validation/wifi/ci.json index ff2c1d7c9ce..36e91b221cb 100644 --- a/tests/validation/wifi/ci.json +++ b/tests/validation/wifi/ci.json @@ -21,7 +21,7 @@ "hardware": false, "qemu": false }, - "targets": { - "esp32h2": false - } + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] } From 8422b745c24fe6739956d6a317f34ea8df5242e1 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:27:10 -0300 Subject: [PATCH 019/406] Fix touch examples JSON for P4 --- libraries/ESP32/examples/Touch/TouchInterrupt/ci.json | 5 ++++- libraries/ESP32/examples/Touch/TouchRead/ci.json | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json b/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json index c0ecf9fc0a5..4363987f4d6 100644 --- a/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json +++ b/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json @@ -1,5 +1,8 @@ { "requires": [ "CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y" - ] + ], + "targets": { + "esp32p4": false + } } diff --git a/libraries/ESP32/examples/Touch/TouchRead/ci.json b/libraries/ESP32/examples/Touch/TouchRead/ci.json index c0ecf9fc0a5..4363987f4d6 100644 --- a/libraries/ESP32/examples/Touch/TouchRead/ci.json +++ b/libraries/ESP32/examples/Touch/TouchRead/ci.json @@ -1,5 +1,8 @@ { "requires": [ "CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y" - ] + ], + "targets": { + "esp32p4": false + } } From a76b22881a82621e7aaa464e66924690c3e9311c Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 30 Sep 2024 19:21:46 -0300 Subject: [PATCH 020/406] Fix ethernet examples JSON for P4 --- libraries/Ethernet/examples/ETH_LAN8720/ci.json | 5 ++++- libraries/Ethernet/examples/ETH_TLK110/ci.json | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/Ethernet/examples/ETH_LAN8720/ci.json b/libraries/Ethernet/examples/ETH_LAN8720/ci.json index dcdfd06db51..0eab13b8841 100644 --- a/libraries/Ethernet/examples/ETH_LAN8720/ci.json +++ b/libraries/Ethernet/examples/ETH_LAN8720/ci.json @@ -1,5 +1,8 @@ { "requires": [ "CONFIG_ETH_USE_ESP32_EMAC=y" - ] + ], + "targets": { + "esp32p4": false + } } diff --git a/libraries/Ethernet/examples/ETH_TLK110/ci.json b/libraries/Ethernet/examples/ETH_TLK110/ci.json index dcdfd06db51..0eab13b8841 100644 --- a/libraries/Ethernet/examples/ETH_TLK110/ci.json +++ b/libraries/Ethernet/examples/ETH_TLK110/ci.json @@ -1,5 +1,8 @@ { "requires": [ "CONFIG_ETH_USE_ESP32_EMAC=y" - ] + ], + "targets": { + "esp32p4": false + } } From a4cbdaf3a843e20ba1d035425b8b6a5474f9f0c2 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Tue, 1 Oct 2024 11:11:03 +0200 Subject: [PATCH 021/406] fix(HardwareSerial): fix pin remapping in begin() (#10379) The pin remapping functions have to be called as early as possible in the begin() function, to immediately convert the input parameters to the GPIO numbers used everywhere in the core. This issue has always been dormant since the introduction of pin remapping in 2.x via 9b4622d, but was exposed by the proper pin muxing support that is present in the 3.x core. Move the pin remapping function calls earlier in the begin() function to fix this issue. --- cores/esp32/HardwareSerial.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 1f064faada6..2e1f2701e9a 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -291,6 +291,10 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in } #endif + // map logical pins to GPIO numbers + rxPin = digitalPinToGPIONumber(rxPin); + txPin = digitalPinToGPIONumber(txPin); + HSERIAL_MUTEX_LOCK(); // First Time or after end() --> set default Pins if (!uartIsDriverInstalled(_uart)) { @@ -326,9 +330,6 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in } } - // map logical pins to GPIO numbers - rxPin = digitalPinToGPIONumber(rxPin); - txPin = digitalPinToGPIONumber(txPin); // IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified. // it will detach previous UART attached pins From 5a06dd9e57cd16f92c9c43724be7f9b9ed8a908e Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 1 Oct 2024 12:11:21 +0300 Subject: [PATCH 022/406] fix(psram): Init PSRAM before app_main to fix mmu_map (#10390) * fix(psram): Init PSRAM before app_main to fix mmu_map Makes sure that PSRAM is part of the map before app_main is called. * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- cores/esp32/esp32-hal-log.h | 1 + cores/esp32/esp32-hal-misc.c | 12 +++++++++--- cores/esp32/esp32-hal-psram.c | 13 +++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/cores/esp32/esp32-hal-log.h b/cores/esp32/esp32-hal-log.h index b8810c8bba9..da63c6dea94 100644 --- a/cores/esp32/esp32-hal-log.h +++ b/cores/esp32/esp32-hal-log.h @@ -20,6 +20,7 @@ extern "C" { #include "sdkconfig.h" #include "esp_timer.h" +#include "rom/ets_sys.h" #define ARDUHAL_LOG_LEVEL_NONE (0) #define ARDUHAL_LOG_LEVEL_ERROR (1) diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index 82363b97bd0..722e999f63f 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -24,6 +24,7 @@ #ifdef CONFIG_APP_ROLLBACK_ENABLE #include "esp_ota_ops.h" #endif //CONFIG_APP_ROLLBACK_ENABLE +#include "esp_private/startup_internal.h" #ifdef CONFIG_BT_ENABLED #include "esp_bt.h" #endif //CONFIG_BT_ENABLED @@ -249,12 +250,17 @@ extern bool btInUse(); #endif #endif +#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM +#ifndef CONFIG_SPIRAM_BOOT_INIT +ESP_SYSTEM_INIT_FN(init_psram_new, BIT(0), 99) { + return psramInit() ? ESP_OK : ESP_FAIL; +} +#endif +#endif + void initArduino() { //init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz) //ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1; -#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM - psramInit(); -#endif #ifdef CONFIG_APP_ROLLBACK_ENABLE if (!verifyRollbackLater()) { const esp_partition_t *running = esp_ota_get_running_partition(); diff --git a/cores/esp32/esp32-hal-psram.c b/cores/esp32/esp32-hal-psram.c index 5a741908f07..6b9a1fb7e8f 100644 --- a/cores/esp32/esp32-hal-psram.c +++ b/cores/esp32/esp32-hal-psram.c @@ -31,6 +31,8 @@ #error Target CONFIG_IDF_TARGET is not supported #endif +#define TAG "arduino-psram" + static volatile bool spiramDetected = false; static volatile bool spiramFailed = false; @@ -52,7 +54,7 @@ bool psramInit() { uint32_t pkg_ver = chip_ver & 0x7; if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) { spiramFailed = true; - log_w("PSRAM not supported!"); + ESP_EARLY_LOGW(TAG, "PSRAM not supported!"); return false; } #elif CONFIG_IDF_TARGET_ESP32S2 @@ -62,7 +64,7 @@ bool psramInit() { #endif if (esp_psram_init() != ESP_OK) { spiramFailed = true; - log_w("PSRAM init failed!"); + ESP_EARLY_LOGW(TAG, "PSRAM init failed!"); #if CONFIG_IDF_TARGET_ESP32 if (pkg_ver != EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) { pinMatrixOutDetach(16, false, false); @@ -71,23 +73,22 @@ bool psramInit() { #endif return false; } - //testSPIRAM() allows user to bypass SPI RAM test routine if (!testSPIRAM()) { spiramFailed = true; - log_e("PSRAM test failed!"); + ESP_EARLY_LOGE(TAG, "PSRAM test failed!"); return false; } if (esp_psram_extram_add_to_heap_allocator() != ESP_OK) { spiramFailed = true; - log_e("PSRAM could not be added to the heap!"); + ESP_EARLY_LOGE(TAG, "PSRAM could not be added to the heap!"); return false; } #if CONFIG_SPIRAM_USE_MALLOC && !CONFIG_ARDUINO_ISR_IRAM heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); #endif + ESP_EARLY_LOGI(TAG, "PSRAM enabled"); #endif /* CONFIG_SPIRAM_BOOT_INIT */ - log_i("PSRAM enabled"); spiramDetected = true; return true; } From c980fdc99691fc797f1d56a03ea18c4893c4d598 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 1 Oct 2024 12:34:44 +0300 Subject: [PATCH 023/406] Update early system init function declaration --- cores/esp32/esp32-hal-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index acc908d2093..d3782c39aa3 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -254,7 +254,7 @@ extern bool btInUse(); #if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM #ifndef CONFIG_SPIRAM_BOOT_INIT -ESP_SYSTEM_INIT_FN(init_psram_new, BIT(0), 99) { +ESP_SYSTEM_INIT_FN(init_psram_new, CORE, BIT(0), 99) { return psramInit() ? ESP_OK : ESP_FAIL; } #endif From 482c0a3c26d9f69a6e4b3cc7da92a5545d16f27a Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 1 Oct 2024 15:43:05 +0300 Subject: [PATCH 024/406] fix(psram): Do not abort if PSRAM is not found Also add to heap in app_main --- cores/esp32/esp32-hal-misc.c | 8 +++++++- cores/esp32/esp32-hal-psram.c | 18 +++++++++++++----- cores/esp32/esp32-hal-psram.h | 1 + 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index d3782c39aa3..1fb1d2af9df 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -255,7 +255,8 @@ extern bool btInUse(); #if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM #ifndef CONFIG_SPIRAM_BOOT_INIT ESP_SYSTEM_INIT_FN(init_psram_new, CORE, BIT(0), 99) { - return psramInit() ? ESP_OK : ESP_FAIL; + psramInit(); + return ESP_OK; } #endif #endif @@ -263,6 +264,11 @@ ESP_SYSTEM_INIT_FN(init_psram_new, CORE, BIT(0), 99) { void initArduino() { //init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz) //ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1; +#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM +#ifndef CONFIG_SPIRAM_BOOT_INIT + psramAddToHeap(); +#endif +#endif #ifdef CONFIG_APP_ROLLBACK_ENABLE if (!verifyRollbackLater()) { const esp_partition_t *running = esp_ota_get_running_partition(); diff --git a/cores/esp32/esp32-hal-psram.c b/cores/esp32/esp32-hal-psram.c index d2c5ab96fc3..6b0b631791b 100644 --- a/cores/esp32/esp32-hal-psram.c +++ b/cores/esp32/esp32-hal-psram.c @@ -81,17 +81,25 @@ bool psramInit() { ESP_EARLY_LOGE(TAG, "PSRAM test failed!"); return false; } + ESP_EARLY_LOGI(TAG, "PSRAM enabled"); +#endif /* CONFIG_SPIRAM_BOOT_INIT */ + spiramDetected = true; + return true; +} + +bool psramAddToHeap() { + if (!spiramDetected) { + log_e("PSRAM not initialized!"); + return false; + } if (esp_psram_extram_add_to_heap_allocator() != ESP_OK) { - spiramFailed = true; - ESP_EARLY_LOGE(TAG, "PSRAM could not be added to the heap!"); + log_e("PSRAM could not be added to the heap!"); return false; } #if CONFIG_SPIRAM_USE_MALLOC && !CONFIG_ARDUINO_ISR_IRAM heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); #endif - ESP_EARLY_LOGI(TAG, "PSRAM enabled"); -#endif /* CONFIG_SPIRAM_BOOT_INIT */ - spiramDetected = true; + log_i("PSRAM added to the heap."); return true; } diff --git a/cores/esp32/esp32-hal-psram.h b/cores/esp32/esp32-hal-psram.h index 0ba6763c69f..e82af1342c2 100644 --- a/cores/esp32/esp32-hal-psram.h +++ b/cores/esp32/esp32-hal-psram.h @@ -31,6 +31,7 @@ extern "C" { #endif bool psramInit(); +bool psramAddToHeap(); bool psramFound(); void *ps_malloc(size_t size); From 753e2032e731f7ca1a5318a735f9175babc0aa3f Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 1 Oct 2024 16:11:59 +0300 Subject: [PATCH 025/406] fix(psram): ESP32-S2 does not like to early debug log --- cores/esp32/esp32-hal-psram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-psram.c b/cores/esp32/esp32-hal-psram.c index 6b0b631791b..3c7a51c3343 100644 --- a/cores/esp32/esp32-hal-psram.c +++ b/cores/esp32/esp32-hal-psram.c @@ -81,7 +81,7 @@ bool psramInit() { ESP_EARLY_LOGE(TAG, "PSRAM test failed!"); return false; } - ESP_EARLY_LOGI(TAG, "PSRAM enabled"); + //ESP_EARLY_LOGI(TAG, "PSRAM enabled"); #endif /* CONFIG_SPIRAM_BOOT_INIT */ spiramDetected = true; return true; From 84ddf0ad282688e25aecfcc264212b80fef62a53 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 1 Oct 2024 16:34:41 +0300 Subject: [PATCH 026/406] fix(psram): Do not abort if PSRAM is not found (#10395) Also add to heap in app_main --- cores/esp32/esp32-hal-misc.c | 8 +++++++- cores/esp32/esp32-hal-psram.c | 18 +++++++++++++----- cores/esp32/esp32-hal-psram.h | 1 + 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index 722e999f63f..dd7a87a4f22 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -253,7 +253,8 @@ extern bool btInUse(); #if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM #ifndef CONFIG_SPIRAM_BOOT_INIT ESP_SYSTEM_INIT_FN(init_psram_new, BIT(0), 99) { - return psramInit() ? ESP_OK : ESP_FAIL; + psramInit(); + return ESP_OK; } #endif #endif @@ -261,6 +262,11 @@ ESP_SYSTEM_INIT_FN(init_psram_new, BIT(0), 99) { void initArduino() { //init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz) //ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1; +#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM +#ifndef CONFIG_SPIRAM_BOOT_INIT + psramAddToHeap(); +#endif +#endif #ifdef CONFIG_APP_ROLLBACK_ENABLE if (!verifyRollbackLater()) { const esp_partition_t *running = esp_ota_get_running_partition(); diff --git a/cores/esp32/esp32-hal-psram.c b/cores/esp32/esp32-hal-psram.c index 6b9a1fb7e8f..b1b13f53ef3 100644 --- a/cores/esp32/esp32-hal-psram.c +++ b/cores/esp32/esp32-hal-psram.c @@ -79,17 +79,25 @@ bool psramInit() { ESP_EARLY_LOGE(TAG, "PSRAM test failed!"); return false; } + ESP_EARLY_LOGI(TAG, "PSRAM enabled"); +#endif /* CONFIG_SPIRAM_BOOT_INIT */ + spiramDetected = true; + return true; +} + +bool psramAddToHeap() { + if (!spiramDetected) { + log_e("PSRAM not initialized!"); + return false; + } if (esp_psram_extram_add_to_heap_allocator() != ESP_OK) { - spiramFailed = true; - ESP_EARLY_LOGE(TAG, "PSRAM could not be added to the heap!"); + log_e("PSRAM could not be added to the heap!"); return false; } #if CONFIG_SPIRAM_USE_MALLOC && !CONFIG_ARDUINO_ISR_IRAM heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); #endif - ESP_EARLY_LOGI(TAG, "PSRAM enabled"); -#endif /* CONFIG_SPIRAM_BOOT_INIT */ - spiramDetected = true; + log_i("PSRAM added to the heap."); return true; } diff --git a/cores/esp32/esp32-hal-psram.h b/cores/esp32/esp32-hal-psram.h index 0ba6763c69f..e82af1342c2 100644 --- a/cores/esp32/esp32-hal-psram.h +++ b/cores/esp32/esp32-hal-psram.h @@ -31,6 +31,7 @@ extern "C" { #endif bool psramInit(); +bool psramAddToHeap(); bool psramFound(); void *ps_malloc(size_t size); From cd971319cbc19b7a7c54b46c9e7d7d38e5b6d01f Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 2 Oct 2024 15:26:32 +0300 Subject: [PATCH 027/406] Fix WPS example config initialization (#10399) * fix(wps): fixes wps struct initialization C99 complaint * fix(wps): adds memset to 0 --------- Co-authored-by: Rodrigo Garcia --- libraries/WiFi/examples/WPS/WPS.ino | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/WiFi/examples/WPS/WPS.ino b/libraries/WiFi/examples/WPS/WPS.ino index 1a6cc6114ee..fc353dcbfb8 100644 --- a/libraries/WiFi/examples/WPS/WPS.ino +++ b/libraries/WiFi/examples/WPS/WPS.ino @@ -25,7 +25,15 @@ WPS (pin is 00000000) #define ESP_WPS_MODE WPS_TYPE_PBC void wpsStart() { - esp_wps_config_t config = WPS_CONFIG_INIT_DEFAULT(ESP_WPS_MODE); + esp_wps_config_t config; + memset(&config, 0, sizeof(esp_wps_config_t)); + //Same as config = WPS_CONFIG_INIT_DEFAULT(ESP_WPS_MODE); + config.wps_type = ESP_WPS_MODE; + strcpy(config.factory_info.manufacturer, "ESPRESSIF"); + strcpy(config.factory_info.model_number, CONFIG_IDF_TARGET); + strcpy(config.factory_info.model_name, "ESPRESSIF IOT"); + strcpy(config.factory_info.device_name, "ESP DEVICE"); + strcpy(config.pin, "00000000"); esp_err_t err = esp_wifi_wps_enable(&config); if (err != ESP_OK) { Serial.printf("WPS Enable Failed: 0x%x: %s\n", err, esp_err_to_name(err)); From 2ec5584d06c50e1a38568f387de82841695de41a Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 2 Oct 2024 15:34:27 +0300 Subject: [PATCH 028/406] fix(hid): Fix OUTPUT report not received (#10398) Fixes an issue where the keyboard LEDs will not trigger the proper event --- cores/esp32/esp32-hal-tinyusb.c | 10 +++++++++- libraries/USB/src/USBHID.cpp | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index 4b39da82641..f7225425913 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -453,7 +453,15 @@ __attribute__((weak)) int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cm __attribute__((weak)) bool tud_msc_is_writable_cb(uint8_t lun) { return false; } - +#endif +#if CFG_TUD_NCM +__attribute__((weak)) bool tud_network_recv_cb(const uint8_t *src, uint16_t size) { + return false; +} +__attribute__((weak)) uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) { + return 0; +} +__attribute__((weak)) void tud_network_init_cb(void) {} #endif /* diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index 995700de4c9..75f37ef5df3 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -259,7 +259,7 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t // Invoked when received SET_REPORT control request or // received data on OUT endpoint ( Report ID = 0, Type = 0 ) void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { - if (!report_id && !report_type) { + if (!report_id && (!report_type || report_type == HID_REPORT_TYPE_OUTPUT)) { if (!tinyusb_on_set_output(0, buffer, bufsize) && !tinyusb_on_set_output(buffer[0], buffer + 1, bufsize - 1)) { log_d( "instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, buffer[0], tinyusb_hid_device_report_types[HID_REPORT_TYPE_OUTPUT], bufsize - 1 From 8af91fb4a7fb9554bf776977ebd432ef1de2a473 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 1 Oct 2024 12:50:04 +0300 Subject: [PATCH 029/406] Fix build of camera web server --- .../ESP32/examples/Camera/CameraWebServer/ci.json | 15 +++++++++++++++ .../Camera/CameraWebServer/partitions.csv | 5 +++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/ci.json b/libraries/ESP32/examples/Camera/CameraWebServer/ci.json index 7e0f3c89986..35c3056dda8 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/ci.json +++ b/libraries/ESP32/examples/Camera/CameraWebServer/ci.json @@ -1,4 +1,19 @@ { + "fqbn": { + "esp32": [ + "espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=custom,FlashMode=dio", + "espressif:esp32:esp32:PSRAM=disabled,PartitionScheme=custom,FlashMode=dio" + ], + "esp32s2": [ + "espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=custom,FlashMode=dio", + "espressif:esp32:esp32s2:PSRAM=disabled,PartitionScheme=custom,FlashMode=dio" + ], + "esp32s3": [ + "espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=custom,FlashMode=qio", + "espressif:esp32:esp32s3:PSRAM=enabled,USBMode=default,PartitionScheme=custom,FlashMode=qio", + "espressif:esp32:esp32s3:PSRAM=disabled,USBMode=default,PartitionScheme=custom,FlashMode=qio" + ] + }, "requires": [ "CONFIG_CAMERA_TASK_STACK_SIZE=[0-9]+" ] diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv b/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv index 4f76ca6d746..b9f18c465a7 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv +++ b/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv @@ -1,5 +1,6 @@ # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, -app0, app, ota_0, 0x10000, 0x3d0000, -fr, data, , 0x3e0000, 0x20000, +app0, app, ota_0, 0x10000, 0x3c0000, +fr, data, , 0x3d0000, 0x20000, +coredump, data, coredump,0x3f0000, 0x10000, From 19f611d7ee847b8e74fb28ab88cc6b9db0c9474d Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 26 Sep 2024 07:54:52 -0300 Subject: [PATCH 030/406] fix(5.1): ESP32 redefinition to ESP32 --- platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index 073d5fd41c7..873e27b0ecb 100644 --- a/platform.txt +++ b/platform.txt @@ -103,7 +103,7 @@ build.code_debug=0 build.defines= build.loop_core= build.event_core= -build.extra_flags=-DARDUINO_HOST_OS="{runtime.os}" -DARDUINO_FQBN="{build.fqbn}" -DESP32 -DCORE_DEBUG_LEVEL={build.code_debug} {build.loop_core} {build.event_core} {build.defines} {build.extra_flags.{build.mcu}} {build.zigbee_mode} +build.extra_flags=-DARDUINO_HOST_OS="{runtime.os}" -DARDUINO_FQBN="{build.fqbn}" -DESP32=ESP32 -DCORE_DEBUG_LEVEL={build.code_debug} {build.loop_core} {build.event_core} {build.defines} {build.extra_flags.{build.mcu}} {build.zigbee_mode} build.extra_libs= build.memory_type={build.boot}_qspi From 58c0bbc0e9a30e7451bcae81a394c05f63541d33 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 2 Oct 2024 16:17:12 +0300 Subject: [PATCH 031/406] fix(usb): Add support for ESP32-P4 to esp32-hal-tinyusb --- CMakeLists.txt | 2 +- cores/esp32/esp32-hal-tinyusb.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ae2df0717b..707e3fe6233 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -343,7 +343,7 @@ function(maybe_add_component component_name) endif() endfunction() -if(IDF_TARGET MATCHES "esp32s2|esp32s3" AND CONFIG_TINYUSB_ENABLED) +if(IDF_TARGET MATCHES "esp32s2|esp32s3|esp32p4" AND CONFIG_TINYUSB_ENABLED) maybe_add_component(arduino_tinyusb) endif() if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_ArduinoOTA) diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index f7225425913..4247a299df0 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -10,12 +10,15 @@ #include "soc/soc.h" #include "soc/efuse_reg.h" +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #include "soc/rtc_cntl_reg.h" #include "soc/usb_struct.h" #include "soc/usb_reg.h" #include "soc/usb_wrap_reg.h" #include "soc/usb_wrap_struct.h" #include "soc/usb_periph.h" +#endif + #include "soc/periph_defs.h" #include "soc/timer_group_struct.h" #include "soc/system_reg.h" @@ -34,8 +37,8 @@ #include "esp32-hal.h" #include "esp32-hal-periman.h" - #include "esp32-hal-tinyusb.h" + #if CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/usb/usb_persist.h" #include "esp32s2/rom/usb/usb_dc.h" @@ -50,6 +53,7 @@ #include "esp32s3/rom/usb/usb_persist.h" #include "esp32s3/rom/usb/usb_dc.h" #include "esp32s3/rom/usb/chip_usb_dw_wrapper.h" +#elif CONFIG_IDF_TARGET_ESP32P4 #endif typedef enum { @@ -467,8 +471,10 @@ __attribute__((weak)) void tud_network_init_cb(void) {} /* * Private API * */ +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 static bool usb_persist_enabled = false; static restart_type_t usb_persist_mode = RESTART_NO_PERSIST; +#endif #if CONFIG_IDF_TARGET_ESP32S3 @@ -549,6 +555,7 @@ static void usb_switch_to_cdc_jtag() { } #endif +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 static void IRAM_ATTR usb_persist_shutdown_handler(void) { if (usb_persist_mode != RESTART_NO_PERSIST) { if (usb_persist_enabled) { @@ -580,8 +587,10 @@ static void IRAM_ATTR usb_persist_shutdown_handler(void) { } } } +#endif void usb_persist_restart(restart_type_t mode) { +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 if (mode < RESTART_TYPE_MAX && esp_register_shutdown_handler(usb_persist_shutdown_handler) == ESP_OK) { usb_persist_mode = mode; #if CONFIG_IDF_TARGET_ESP32S3 @@ -591,6 +600,7 @@ void usb_persist_restart(restart_type_t mode) { #endif esp_restart(); } +#endif } static bool tinyusb_reserve_in_endpoint(uint8_t endpoint) { @@ -674,8 +684,13 @@ static inline char nibble_to_hex_char(uint8_t b) { static void set_usb_serial_num(void) { /* Get the MAC address */ +#if CONFIG_IDF_TARGET_ESP32P4 + const uint32_t mac0 = REG_GET_FIELD(EFUSE_RD_MAC_SYS_0_REG, EFUSE_MAC_0); + const uint32_t mac1 = REG_GET_FIELD(EFUSE_RD_MAC_SYS_0_REG, EFUSE_MAC_1); +#else const uint32_t mac0 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_MAC_0); const uint32_t mac1 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_1_REG, EFUSE_MAC_1); +#endif uint8_t mac_bytes[6]; memcpy(mac_bytes, &mac0, 4); memcpy(mac_bytes + 4, &mac1, 2); @@ -794,6 +809,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { return ESP_FAIL; } +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA); //if(usb_did_persist && usb_persist_enabled){ @@ -806,7 +822,8 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { periph_ll_reset(PERIPH_USB_MODULE); periph_ll_enable_clk_clear_rst(PERIPH_USB_MODULE); } - +#endif + tinyusb_config_t tusb_cfg = { .external_phy = false // In the most cases you need to use a `false` value }; From 473b8515ac4ba956b36c97bb94c6db5e287c3920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:00:39 +0200 Subject: [PATCH 032/406] feat(zigbee): Add Zigbee library (#10265) * Initial commit - light bulb + switch working * Add Thermostat + fix enum * Dev update: roles, cb removal, handlers Fixed ep_thermostat to compile successfully Removed cb from all EP, as it have been removed, virtual methods will be used instead. Moved zigbee handlers out of Zigbee_core to Zigbee_handlers for better readability. Fixed zigbeeInit to be bool and return status of initialization for begin function. Updated examples with edited roles and custom method for on_off light * Dev update: implement on/off light and switch methods Implemented basic function calls of switch commands to on/off light: lightToggle, lightOn, lightOff, ... Implemented virtual methods for on/off light that have to be override in user code: setOnOff, sceneControl, setOnOffTime, setOffWaitTime APIs can be changed, still early development. * Dev update: Factory reset, names, multiple EPs Implemented Factory reset of Zigbee device, in order to connect to new network without reflashing/erasing flash Implemented optional setting for Manufacturer and Model names Added option to allow endpoint to have multiple endpoint connected -> switch - 2 lights (tested) Minor sketches update * Dev update: Device ID to string Implemented easy transfer from device it to Device type (0x0000 = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID -> "General On/Off switch". * Implement cmd default response handler * Remove unused _identify_cluster * Dev Update: Color DImmable light + switch implemented Implemeted color dimmable light and color dimmer switch HA devices + examples. Removed unnecessary stored attribute cluster Renamed on/off light and switch examples * Implement Network Scanning Implemented Zigbee network scanning (async) to mostly match WiFi scan APIs. Added Zigbee_Scan_Networks example * Dev Update: Thermostat and Temperature sensor EP Implemeted thermostat and temperature sensor HA devices + examples. Implemented configure report handler. Updated READMEs and description of examples. Minor code updates * fix(): Replace deprecated function * Remove ported IDF examples * Update Zigbee examples with new APIs * Dev Update: Version setting, Thermostat fix, ... Simplified bounded device print as the structure is common for any EP type Allowed setting custom app version for EP, default is 0 Small fixes and code updates * Remove EP template + add lib to CMakeLists * Rename classes to have proper naming * Add check for SOC_IEEE802154_SUPPORTED * Ignore false positive unused variable/function * Fix compilation errors in examples * Fill keyworkds.txt, remove unnecessary defines * Rename methods, variables + make private/protected * Remove unnecesary defaults defines * Remove outdated comments * Update Scan networks Readme * fix(example): Use proper naming of func and variables * Change virtual methods to callbacks (TODO) * Refactor classes methods + implement Identify command * Apply suggestions from code review by @lucasssvaz Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * Update READMEs + add openNetwork fucntion * Use [[maybe_unused]] instead of #pragma * Use gpio calls for OnOff Light example * ci(pre-commit): Apply automatic fixes * fix(): Codespell issues --------- Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> --- CMakeLists.txt | 13 + boards.txt | 84 +-- .../Zigbee_Light_Bulb/Zigbee_Light_Bulb.ino | 183 ------ .../examples/Zigbee/Zigbee_Light_Bulb/ci.json | 10 - .../Zigbee_Light_Switch.ino | 296 --------- .../Zigbee/Zigbee_Light_Switch/ci.json | 10 - .../Zigbee_Temperature_Sensor.ino | 349 ----------- .../Zigbee/Zigbee_Temperature_Sensor/ci.json | 10 - .../Zigbee_Thermostat/Zigbee_Thermostat.ino | 565 ------------------ .../examples/Zigbee/Zigbee_Thermostat/ci.json | 10 - .../Zigbee_Color_Dimmable_Light/README.md | 68 +++ .../Zigbee_Color_Dimmable_Light.ino | 104 ++++ .../Zigbee_Color_Dimmable_Light/ci.json | 16 + .../Zigbee_Color_Dimmer_Switch/README.md | 68 +++ .../Zigbee_Color_Dimmer_Switch.ino | 148 +++++ .../Zigbee_Color_Dimmer_Switch/ci.json | 16 + .../examples/Zigbee_On_Off_Light}/README.md | 35 +- .../Zigbee_On_Off_Light.ino | 87 +++ .../examples/Zigbee_On_Off_Light/ci.json | 16 + .../examples/Zigbee_On_Off_Switch}/README.md | 35 +- .../Zigbee_On_Off_Switch.ino | 194 ++++++ .../examples/Zigbee_On_Off_Switch/ci.json | 16 + .../examples/Zigbee_Scan_Networks/README.md | 71 +++ .../Zigbee_Scan_Networks.ino | 113 ++++ .../examples/Zigbee_Scan_Networks/ci.json | 16 + .../Zigbee_Temperature_Sensor/README.md | 36 +- .../Zigbee_Temperature_Sensor.ino | 107 ++++ .../Zigbee_Temperature_Sensor/ci.json | 16 + .../examples}/Zigbee_Thermostat/README.md | 27 +- .../Zigbee_Thermostat/Zigbee_Thermostat.ino | 119 ++++ .../Zigbee/examples/Zigbee_Thermostat/ci.json | 16 + libraries/Zigbee/keywords.txt | 105 ++++ libraries/Zigbee/library.properties | 9 + libraries/Zigbee/src/ZigbeeCore.cpp | 396 ++++++++++++ libraries/Zigbee/src/ZigbeeCore.h | 125 ++++ libraries/Zigbee/src/ZigbeeEP.cpp | 162 +++++ libraries/Zigbee/src/ZigbeeEP.h | 124 ++++ libraries/Zigbee/src/ZigbeeHandlers.cpp | 141 +++++ .../src/ep/ZigbeeColorDimmableLight.cpp | 112 ++++ .../Zigbee/src/ep/ZigbeeColorDimmableLight.h | 41 ++ .../Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp | 403 +++++++++++++ .../Zigbee/src/ep/ZigbeeColorDimmerSwitch.h | 60 ++ libraries/Zigbee/src/ep/ZigbeeLight.cpp | 35 ++ libraries/Zigbee/src/ep/ZigbeeLight.h | 33 + libraries/Zigbee/src/ep/ZigbeeSwitch.cpp | 233 ++++++++ libraries/Zigbee/src/ep/ZigbeeSwitch.h | 42 ++ libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp | 93 +++ libraries/Zigbee/src/ep/ZigbeeTempSensor.h | 30 + libraries/Zigbee/src/ep/ZigbeeThermostat.cpp | 205 +++++++ libraries/Zigbee/src/ep/ZigbeeThermostat.h | 64 ++ 50 files changed, 3718 insertions(+), 1549 deletions(-) delete mode 100644 libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/Zigbee_Light_Bulb.ino delete mode 100644 libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/ci.json delete mode 100644 libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/Zigbee_Light_Switch.ino delete mode 100644 libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/ci.json delete mode 100644 libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino delete mode 100644 libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/ci.json delete mode 100644 libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/Zigbee_Thermostat.ino delete mode 100644 libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/ci.json create mode 100644 libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/README.md create mode 100644 libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino create mode 100644 libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json create mode 100644 libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/README.md create mode 100644 libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino create mode 100644 libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json rename libraries/{ESP32/examples/Zigbee/Zigbee_Light_Bulb => Zigbee/examples/Zigbee_On_Off_Light}/README.md (62%) create mode 100644 libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino create mode 100644 libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json rename libraries/{ESP32/examples/Zigbee/Zigbee_Light_Switch => Zigbee/examples/Zigbee_On_Off_Switch}/README.md (57%) create mode 100644 libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino create mode 100644 libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json create mode 100644 libraries/Zigbee/examples/Zigbee_Scan_Networks/README.md create mode 100644 libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino create mode 100644 libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json rename libraries/{ESP32/examples/Zigbee => Zigbee/examples}/Zigbee_Temperature_Sensor/README.md (59%) create mode 100644 libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino create mode 100644 libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json rename libraries/{ESP32/examples/Zigbee => Zigbee/examples}/Zigbee_Thermostat/README.md (64%) create mode 100644 libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino create mode 100644 libraries/Zigbee/examples/Zigbee_Thermostat/ci.json create mode 100644 libraries/Zigbee/keywords.txt create mode 100644 libraries/Zigbee/library.properties create mode 100644 libraries/Zigbee/src/ZigbeeCore.cpp create mode 100644 libraries/Zigbee/src/ZigbeeCore.h create mode 100644 libraries/Zigbee/src/ZigbeeEP.cpp create mode 100644 libraries/Zigbee/src/ZigbeeEP.h create mode 100644 libraries/Zigbee/src/ZigbeeHandlers.cpp create mode 100644 libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp create mode 100644 libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h create mode 100644 libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp create mode 100644 libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h create mode 100644 libraries/Zigbee/src/ep/ZigbeeLight.cpp create mode 100644 libraries/Zigbee/src/ep/ZigbeeLight.h create mode 100644 libraries/Zigbee/src/ep/ZigbeeSwitch.cpp create mode 100644 libraries/Zigbee/src/ep/ZigbeeSwitch.h create mode 100644 libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp create mode 100644 libraries/Zigbee/src/ep/ZigbeeTempSensor.h create mode 100644 libraries/Zigbee/src/ep/ZigbeeThermostat.cpp create mode 100644 libraries/Zigbee/src/ep/ZigbeeThermostat.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bfb3ee4ff28..9a858ee79cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,6 +112,7 @@ set(ARDUINO_ALL_LIBRARIES WiFi WiFiProv Wire + Zigbee ) set(ARDUINO_LIBRARY_ArduinoOTA_SRCS libraries/ArduinoOTA/src/ArduinoOTA.cpp) @@ -240,6 +241,18 @@ set(ARDUINO_LIBRARY_WiFiProv_SRCS libraries/WiFiProv/src/WiFiProv.cpp) set(ARDUINO_LIBRARY_Wire_SRCS libraries/Wire/src/Wire.cpp) +set(ARDUINO_LIBRARY_Zigbee_SRCS + libraries/Zigbee/src/ZigbeeCore.cpp + libraries/Zigbee/src/ZigbeeEP.cpp + libraries/Zigbee/src/ZigbeeHandlers.cpp + libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp + libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp + libraries/Zigbee/src/ep/ZigbeeLight.cpp + libraries/Zigbee/src/ep/ZigbeeSwitch.cpp + libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp + libraries/Zigbee/src/ep/ZigbeeThermostat.cpp + ) + set(ARDUINO_LIBRARY_BLE_SRCS libraries/BLE/src/BLE2901.cpp libraries/BLE/src/BLE2902.cpp diff --git a/boards.txt b/boards.txt index 0e873f0110b..c785e4d80a4 100644 --- a/boards.txt +++ b/boards.txt @@ -339,7 +339,7 @@ esp32h2.menu.ZigbeeMode.default.build.zigbee_libs= esp32h2.menu.ZigbeeMode.ed=Zigbee ED (end device) esp32h2.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED esp32h2.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -esp32h2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32h2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32h2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32h2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port esp32h2.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -533,7 +533,7 @@ esp32c6.menu.ZigbeeMode.default.build.zigbee_libs= esp32c6.menu.ZigbeeMode.ed=Zigbee ED (end device) esp32c6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED esp32c6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32c6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port esp32c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -789,7 +789,7 @@ esp32s3.menu.EraseFlash.all.upload.erase_cmd=-e esp32s3.menu.ZigbeeMode.default=Disabled esp32s3.menu.ZigbeeMode.default.build.zigbee_mode= esp32s3.menu.ZigbeeMode.default.build.zigbee_libs= -esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32s3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32s3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -971,7 +971,7 @@ esp32c3.menu.EraseFlash.all.upload.erase_cmd=-e esp32c3.menu.ZigbeeMode.default=Disabled esp32c3.menu.ZigbeeMode.default.build.zigbee_mode= esp32c3.menu.ZigbeeMode.default.build.zigbee_libs= -esp32c3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32c3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32c3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32c3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -1180,7 +1180,7 @@ esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e esp32s2.menu.ZigbeeMode.default=Disabled esp32s2.menu.ZigbeeMode.default.build.zigbee_mode= esp32s2.menu.ZigbeeMode.default.build.zigbee_libs= -esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32s2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32s2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -1376,7 +1376,7 @@ esp32.menu.EraseFlash.all.upload.erase_cmd=-e esp32.menu.ZigbeeMode.default=Disabled esp32.menu.ZigbeeMode.default.build.zigbee_mode= esp32.menu.ZigbeeMode.default.build.zigbee_libs= -esp32.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -4287,7 +4287,7 @@ um_tinyc6.menu.ZigbeeMode.default.build.zigbee_libs= um_tinyc6.menu.ZigbeeMode.ed=Zigbee ED (end device) um_tinyc6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED um_tinyc6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -um_tinyc6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +um_tinyc6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) um_tinyc6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR um_tinyc6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port um_tinyc6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -7302,7 +7302,7 @@ sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.default.build.zigbee_libs= sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.ed=Zigbee ED (end device) sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port sparkfun_esp32c6_thing_plus.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -7901,7 +7901,7 @@ sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.default.build.zigbee_libs= sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.ed=Zigbee ED (end device) sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port sparkfun_esp32c6_qwiic_pocket.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -11139,7 +11139,7 @@ dfrobot_beetle_esp32c6.menu.ZigbeeMode.default.build.zigbee_libs= dfrobot_beetle_esp32c6.menu.ZigbeeMode.ed=Zigbee ED (end device) dfrobot_beetle_esp32c6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED dfrobot_beetle_esp32c6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -dfrobot_beetle_esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +dfrobot_beetle_esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) dfrobot_beetle_esp32c6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR dfrobot_beetle_esp32c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port dfrobot_beetle_esp32c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -11691,7 +11691,7 @@ dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.default.build.zigbee_libs= dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.ed=Zigbee ED (end device) dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port dfrobot_firebeetle2_esp32c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -12290,7 +12290,7 @@ adafruit_metro_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_metro_esp32s2.menu.ZigbeeMode.default=Disabled adafruit_metro_esp32s2.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_metro_esp32s2.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_metro_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_metro_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_metro_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_metro_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -12493,7 +12493,7 @@ adafruit_metro_esp32s3.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_metro_esp32s3.menu.ZigbeeMode.default=Disabled adafruit_metro_esp32s3.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_metro_esp32s3.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_metro_esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_metro_esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_metro_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_metro_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -12676,7 +12676,7 @@ adafruit_magtag29_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_magtag29_esp32s2.menu.ZigbeeMode.default=Disabled adafruit_magtag29_esp32s2.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_magtag29_esp32s2.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_magtag29_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_magtag29_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_magtag29_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_magtag29_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -12859,7 +12859,7 @@ adafruit_funhouse_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_funhouse_esp32s2.menu.ZigbeeMode.default=Disabled adafruit_funhouse_esp32s2.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_funhouse_esp32s2.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_funhouse_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_funhouse_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_funhouse_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_funhouse_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -12993,7 +12993,7 @@ featheresp32.menu.EraseFlash.all.upload.erase_cmd=-e featheresp32.menu.ZigbeeMode.default=Disabled featheresp32.menu.ZigbeeMode.default.build.zigbee_mode= featheresp32.menu.ZigbeeMode.default.build.zigbee_libs= -featheresp32.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +featheresp32.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) featheresp32.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR featheresp32.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -13111,7 +13111,7 @@ adafruit_feather_esp32_v2.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_feather_esp32_v2.menu.ZigbeeMode.default=Disabled adafruit_feather_esp32_v2.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_feather_esp32_v2.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_feather_esp32_v2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32_v2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32_v2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32_v2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -13294,7 +13294,7 @@ adafruit_feather_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_feather_esp32s2.menu.ZigbeeMode.default=Disabled adafruit_feather_esp32s2.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_feather_esp32s2.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_feather_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -13477,7 +13477,7 @@ adafruit_feather_esp32s2_tft.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_feather_esp32s2_tft.menu.ZigbeeMode.default=Disabled adafruit_feather_esp32s2_tft.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_feather_esp32s2_tft.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_feather_esp32s2_tft.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32s2_tft.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32s2_tft.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32s2_tft.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -13660,7 +13660,7 @@ adafruit_feather_esp32s2_reversetft.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_feather_esp32s2_reversetft.menu.ZigbeeMode.default=Disabled adafruit_feather_esp32s2_reversetft.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_feather_esp32s2_reversetft.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_feather_esp32s2_reversetft.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32s2_reversetft.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32s2_reversetft.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32s2_reversetft.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -13878,7 +13878,7 @@ adafruit_feather_esp32s3.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_feather_esp32s3.menu.ZigbeeMode.default=Disabled adafruit_feather_esp32s3.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_feather_esp32s3.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_feather_esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -14065,7 +14065,7 @@ adafruit_feather_esp32s3_nopsram.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_feather_esp32s3_nopsram.menu.ZigbeeMode.default=Disabled adafruit_feather_esp32s3_nopsram.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_feather_esp32s3_nopsram.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_feather_esp32s3_nopsram.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32s3_nopsram.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32s3_nopsram.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32s3_nopsram.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -14283,7 +14283,7 @@ adafruit_feather_esp32s3_tft.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_feather_esp32s3_tft.menu.ZigbeeMode.default=Disabled adafruit_feather_esp32s3_tft.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_feather_esp32s3_tft.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_feather_esp32s3_tft.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32s3_tft.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32s3_tft.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32s3_tft.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -14501,7 +14501,7 @@ adafruit_feather_esp32s3_reversetft.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_feather_esp32s3_reversetft.menu.ZigbeeMode.default=Disabled adafruit_feather_esp32s3_reversetft.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_feather_esp32s3_reversetft.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_feather_esp32s3_reversetft.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32s3_reversetft.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32s3_reversetft.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32s3_reversetft.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -14676,7 +14676,7 @@ adafruit_feather_esp32c6.menu.ZigbeeMode.default.build.zigbee_libs= adafruit_feather_esp32c6.menu.ZigbeeMode.ed=Zigbee ED (end device) adafruit_feather_esp32c6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED adafruit_feather_esp32c6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -adafruit_feather_esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_feather_esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_feather_esp32c6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_feather_esp32c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port adafruit_feather_esp32c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -14799,7 +14799,7 @@ adafruit_qtpy_esp32_pico.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_qtpy_esp32_pico.menu.ZigbeeMode.default=Disabled adafruit_qtpy_esp32_pico.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_qtpy_esp32_pico.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_qtpy_esp32_pico.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_qtpy_esp32_pico.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_qtpy_esp32_pico.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_qtpy_esp32_pico.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -14934,7 +14934,7 @@ adafruit_qtpy_esp32c3.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_qtpy_esp32c3.menu.ZigbeeMode.default=Disabled adafruit_qtpy_esp32c3.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_qtpy_esp32c3.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_qtpy_esp32c3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_qtpy_esp32c3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_qtpy_esp32c3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_qtpy_esp32c3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -15117,7 +15117,7 @@ adafruit_qtpy_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_qtpy_esp32s2.menu.ZigbeeMode.default=Disabled adafruit_qtpy_esp32s2.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_qtpy_esp32s2.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_qtpy_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_qtpy_esp32s2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_qtpy_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_qtpy_esp32s2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -15304,7 +15304,7 @@ adafruit_qtpy_esp32s3_nopsram.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_qtpy_esp32s3_nopsram.menu.ZigbeeMode.default=Disabled adafruit_qtpy_esp32s3_nopsram.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_qtpy_esp32s3_nopsram.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_qtpy_esp32s3_nopsram.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_qtpy_esp32s3_nopsram.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_qtpy_esp32s3_nopsram.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_qtpy_esp32s3_nopsram.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -15522,7 +15522,7 @@ adafruit_qtpy_esp32s3_n4r2.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_qtpy_esp32s3_n4r2.menu.ZigbeeMode.default=Disabled adafruit_qtpy_esp32s3_n4r2.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_qtpy_esp32s3_n4r2.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_qtpy_esp32s3_n4r2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_qtpy_esp32s3_n4r2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_qtpy_esp32s3_n4r2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_qtpy_esp32s3_n4r2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -15640,7 +15640,7 @@ adafruit_itsybitsy_esp32.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_itsybitsy_esp32.menu.ZigbeeMode.default=Disabled adafruit_itsybitsy_esp32.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_itsybitsy_esp32.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_itsybitsy_esp32.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_itsybitsy_esp32.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_itsybitsy_esp32.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_itsybitsy_esp32.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -15837,7 +15837,7 @@ adafruit_matrixportal_esp32s3.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_matrixportal_esp32s3.menu.ZigbeeMode.default=Disabled adafruit_matrixportal_esp32s3.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_matrixportal_esp32s3.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_matrixportal_esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_matrixportal_esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_matrixportal_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_matrixportal_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -16055,7 +16055,7 @@ adafruit_camera_esp32s3.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_camera_esp32s3.menu.ZigbeeMode.default=Disabled adafruit_camera_esp32s3.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_camera_esp32s3.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_camera_esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_camera_esp32s3.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_camera_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_camera_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -16258,7 +16258,7 @@ adafruit_qualia_s3_rgb666.menu.EraseFlash.all.upload.erase_cmd=-e adafruit_qualia_s3_rgb666.menu.ZigbeeMode.default=Disabled adafruit_qualia_s3_rgb666.menu.ZigbeeMode.default.build.zigbee_mode= adafruit_qualia_s3_rgb666.menu.ZigbeeMode.default.build.zigbee_libs= -adafruit_qualia_s3_rgb666.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +adafruit_qualia_s3_rgb666.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) adafruit_qualia_s3_rgb666.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR adafruit_qualia_s3_rgb666.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -16713,7 +16713,7 @@ nologo_esp32s3_pico.menu.EraseFlash.all.upload.erase_cmd=-e nologo_esp32s3_pico.menu.ZigbeeMode.default=Disabled nologo_esp32s3_pico.menu.ZigbeeMode.default.build.zigbee_mode= nologo_esp32s3_pico.menu.ZigbeeMode.default.build.zigbee_libs= -nologo_esp32s3_pico.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +nologo_esp32s3_pico.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) nologo_esp32s3_pico.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR nologo_esp32s3_pico.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -18659,7 +18659,7 @@ esp32c6-evb.menu.ZigbeeMode.default.build.zigbee_libs= esp32c6-evb.menu.ZigbeeMode.ed=Zigbee ED (end device) esp32c6-evb.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED esp32c6-evb.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -esp32c6-evb.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32c6-evb.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32c6-evb.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32c6-evb.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port esp32c6-evb.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -18841,7 +18841,7 @@ esp32h2-devkitlipo.menu.ZigbeeMode.default.build.zigbee_libs= esp32h2-devkitlipo.menu.ZigbeeMode.ed=Zigbee ED (end device) esp32h2-devkitlipo.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED esp32h2-devkitlipo.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -esp32h2-devkitlipo.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32h2-devkitlipo.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32h2-devkitlipo.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32h2-devkitlipo.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port esp32h2-devkitlipo.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -19037,7 +19037,7 @@ esp32-sbc-fabgl.menu.EraseFlash.all.upload.erase_cmd=-e esp32-sbc-fabgl.menu.ZigbeeMode.default=Disabled esp32-sbc-fabgl.menu.ZigbeeMode.default.build.zigbee_mode= esp32-sbc-fabgl.menu.ZigbeeMode.default.build.zigbee_libs= -esp32-sbc-fabgl.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +esp32-sbc-fabgl.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) esp32-sbc-fabgl.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR esp32-sbc-fabgl.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port @@ -23727,7 +23727,7 @@ m5stack_nanoc6.menu.ZigbeeMode.default.build.zigbee_libs= m5stack_nanoc6.menu.ZigbeeMode.ed=Zigbee ED (end device) m5stack_nanoc6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED m5stack_nanoc6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -m5stack_nanoc6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +m5stack_nanoc6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) m5stack_nanoc6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR m5stack_nanoc6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port m5stack_nanoc6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -34157,7 +34157,7 @@ XIAO_ESP32C6.menu.ZigbeeMode.default.build.zigbee_libs= XIAO_ESP32C6.menu.ZigbeeMode.ed=Zigbee ED (end device) XIAO_ESP32C6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED XIAO_ESP32C6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -XIAO_ESP32C6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +XIAO_ESP32C6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) XIAO_ESP32C6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR XIAO_ESP32C6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port XIAO_ESP32C6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -39355,7 +39355,7 @@ epulse_feather_c6.menu.ZigbeeMode.default.build.zigbee_libs= epulse_feather_c6.menu.ZigbeeMode.ed=Zigbee ED (end device) epulse_feather_c6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED epulse_feather_c6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port -epulse_feather_c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +epulse_feather_c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) epulse_feather_c6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR epulse_feather_c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port epulse_feather_c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) @@ -41638,7 +41638,7 @@ jczn_2432s028r.menu.EraseFlash.all.upload.erase_cmd=-e jczn_2432s028r.menu.ZigbeeMode.default=Disabled jczn_2432s028r.menu.ZigbeeMode.default.build.zigbee_mode= jczn_2432s028r.menu.ZigbeeMode.default.build.zigbee_libs= -jczn_2432s028r.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +jczn_2432s028r.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) jczn_2432s028r.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR jczn_2432s028r.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/Zigbee_Light_Bulb.ino b/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/Zigbee_Light_Bulb.ino deleted file mode 100644 index c7e58125ccb..00000000000 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/Zigbee_Light_Bulb.ino +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2023 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @brief This example demonstrates simple Zigbee light bulb. - * - * The example demonstrates how to use ESP Zigbee stack to create a end device light bulb. - * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator. - * - * Proper Zigbee mode must be selected in Tools->Zigbee mode - * and also the correct partition scheme must be selected in Tools->Partition Scheme. - * - * Please check the README.md for instructions and more detailed description. - */ - -#ifndef ZIGBEE_MODE_ED -#error "Zigbee end device mode is not selected in Tools->Zigbee mode" -#endif - -#include "esp_zigbee_core.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "ha/esp_zigbee_ha_standard.h" - -#define LED_PIN RGB_BUILTIN - -/* Default End Device config */ -#define ESP_ZB_ZED_CONFIG() \ - { \ - .esp_zb_role = ESP_ZB_DEVICE_TYPE_ED, .install_code_policy = INSTALLCODE_POLICY_ENABLE, \ - .nwk_cfg = { \ - .zed_cfg = \ - { \ - .ed_timeout = ED_AGING_TIMEOUT, \ - .keep_alive = ED_KEEP_ALIVE, \ - }, \ - }, \ - } - -#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, } - -/* Zigbee configuration */ -#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ -#define ED_AGING_TIMEOUT ESP_ZB_ED_AGING_TIMEOUT_64MIN -#define ED_KEEP_ALIVE 3000 /* 3000 millisecond */ -#define HA_ESP_LIGHT_ENDPOINT 10 /* esp light bulb device endpoint, used to process light controlling commands */ -#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ - -/********************* Zigbee functions **************************/ -static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) { - ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); -} - -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 = (esp_zb_app_signal_type_t)*p_sg_p; - switch (sig_type) { - case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: - log_i("Zigbee stack initialized"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION); - break; - case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: - case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: - if (err_status == ESP_OK) { - log_i("Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non"); - if (esp_zb_bdb_is_factory_new()) { - log_i("Start network formation"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); - } else { - log_i("Device rebooted"); - } - } else { - /* commissioning failed */ - log_w("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); - } - break; - case ESP_ZB_BDB_SIGNAL_STEERING: - if (err_status == ESP_OK) { - esp_zb_ieee_addr_t extended_pan_id; - esp_zb_get_extended_pan_id(extended_pan_id); - log_i( - "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", - 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(), esp_zb_get_short_address() - ); - } else { - log_i("Network steering was not successful (status: %s)", 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); - } - break; - default: log_i("ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); break; - } -} - -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_SET_ATTR_VALUE_CB_ID: ret = zb_attribute_handler((esp_zb_zcl_set_attr_value_message_t *)message); break; - default: log_w("Receive Zigbee action(0x%x) callback", callback_id); break; - } - return ret; -} - -static void esp_zb_task(void *pvParameters) { - esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG(); - esp_zb_init(&zb_nwk_cfg); - esp_zb_on_off_light_cfg_t light_cfg = ESP_ZB_DEFAULT_ON_OFF_LIGHT_CONFIG(); - esp_zb_ep_list_t *esp_zb_on_off_light_ep = esp_zb_on_off_light_ep_create(HA_ESP_LIGHT_ENDPOINT, &light_cfg); - esp_zb_device_register(esp_zb_on_off_light_ep); - esp_zb_core_action_handler_register(zb_action_handler); - esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK); - - //Erase NVRAM before creating connection to new Coordinator - esp_zb_nvram_erase_at_start(true); //Comment out this line to erase NVRAM data if you are connecting to new Coordinator - - ESP_ERROR_CHECK(esp_zb_start(false)); - esp_zb_main_loop_iteration(); -} - -/* Handle the light attribute */ - -static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *message) { - esp_err_t ret = ESP_OK; - bool light_state = 0; - - if (!message) { - log_e("Empty message"); - } - if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) { - log_e("Received message: error status(%d)", message->info.status); - } - - log_i( - "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 == HA_ESP_LIGHT_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) { - light_state = message->attribute.data.value ? *(bool *)message->attribute.data.value : light_state; - log_i("Light sets to %s", light_state ? "On" : "Off"); - rgbLedWrite(LED_PIN, 255 * light_state, 255 * light_state, 255 * light_state); // Toggle light - } - } - } - return ret; -} - -/********************* Arduino functions **************************/ -void setup() { - // Init Zigbee - 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)); - - // Init RMT and leave light OFF - rgbLedWrite(LED_PIN, 0, 0, 0); - - // Start Zigbee task - xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL); -} - -void loop() { - //empty, zigbee running in task -} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/ci.json b/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/ci.json deleted file mode 100644 index 7cfaa76784d..00000000000 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/ci.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } -} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/Zigbee_Light_Switch.ino b/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/Zigbee_Light_Switch.ino deleted file mode 100644 index 83ec1d7aa53..00000000000 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/Zigbee_Light_Switch.ino +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2023 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @brief This example demonstrates simple Zigbee light switch. - * - * The example demonstrates how to use ESP Zigbee stack to control a light bulb. - * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator. - * Button switch and Zigbee runs in separate tasks. - * - * Proper Zigbee mode must be selected in Tools->Zigbee mode - * and also the correct partition scheme must be selected in Tools->Partition Scheme. - * - * Please check the README.md for instructions and more detailed description. - */ - -#ifndef ZIGBEE_MODE_ZCZR -#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" -#endif - -#include "esp_zigbee_core.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "ha/esp_zigbee_ha_standard.h" - -/* Switch configuration */ -#define GPIO_INPUT_IO_TOGGLE_SWITCH GPIO_NUM_9 -#define PAIR_SIZE(TYPE_STR_PAIR) (sizeof(TYPE_STR_PAIR) / sizeof(TYPE_STR_PAIR[0])) - -typedef enum { - SWITCH_ON_CONTROL, - SWITCH_OFF_CONTROL, - SWITCH_ONOFF_TOGGLE_CONTROL, - SWITCH_LEVEL_UP_CONTROL, - SWITCH_LEVEL_DOWN_CONTROL, - SWITCH_LEVEL_CYCLE_CONTROL, - SWITCH_COLOR_CONTROL, -} switch_func_t; - -typedef struct { - uint8_t pin; - switch_func_t func; -} switch_func_pair_t; - -typedef enum { - SWITCH_IDLE, - SWITCH_PRESS_ARMED, - SWITCH_PRESS_DETECTED, - SWITCH_PRESSED, - SWITCH_RELEASE_DETECTED, -} switch_state_t; - -static switch_func_pair_t button_func_pair[] = {{GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL}}; - -/* Default Coordinator config */ -#define ESP_ZB_ZC_CONFIG() \ - { \ - .esp_zb_role = ESP_ZB_DEVICE_TYPE_COORDINATOR, .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, } - -typedef struct light_bulb_device_params_s { - esp_zb_ieee_addr_t ieee_addr; - uint8_t endpoint; - uint16_t short_addr; -} light_bulb_device_params_t; - -/* Zigbee configuration */ -#define MAX_CHILDREN 10 /* the max amount of connected devices */ -#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ -#define HA_ONOFF_SWITCH_ENDPOINT 1 /* esp light switch device endpoint */ -#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ - -/********************* Zigbee functions **************************/ -static void esp_zb_buttons_handler(switch_func_pair_t *button_func_pair) { - if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) { - /* implemented light switch toggle functionality */ - esp_zb_zcl_on_off_cmd_t cmd_req; - cmd_req.zcl_basic_cmd.src_endpoint = HA_ONOFF_SWITCH_ENDPOINT; - cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; - cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; - log_i("Send 'on_off toggle' command"); - esp_zb_zcl_on_off_cmd_req(&cmd_req); - } -} - -static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) { - ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); -} - -static void bind_cb(esp_zb_zdp_status_t zdo_status, void *user_ctx) { - if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { - log_i("Bound successfully!"); - if (user_ctx) { - light_bulb_device_params_t *light = (light_bulb_device_params_t *)user_ctx; - log_i("The light originating from address(0x%x) on endpoint(%d)", light->short_addr, light->endpoint); - free(light); - } - } -} - -static void user_find_cb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { - if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { - log_i("Found light"); - esp_zb_zdo_bind_req_param_t bind_req; - light_bulb_device_params_t *light = (light_bulb_device_params_t *)malloc(sizeof(light_bulb_device_params_t)); - light->endpoint = endpoint; - light->short_addr = addr; - esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr); - esp_zb_get_long_address(bind_req.src_address); - bind_req.src_endp = HA_ONOFF_SWITCH_ENDPOINT; - bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF; - bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; - memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t)); - bind_req.dst_endp = endpoint; - bind_req.req_dst_addr = esp_zb_get_short_address(); - log_i("Try to bind On/Off"); - esp_zb_zdo_device_bind_req(&bind_req, bind_cb, (void *)light); - } -} - -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 = (esp_zb_app_signal_type_t)*p_sg_p; - esp_zb_zdo_signal_device_annce_params_t *dev_annce_params = NULL; - switch (sig_type) { - case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: - log_i("Zigbee stack initialized"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION); - break; - case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: - case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: - if (err_status == ESP_OK) { - log_i("Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non"); - if (esp_zb_bdb_is_factory_new()) { - log_i("Start network formation"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); - } else { - log_i("Device rebooted"); - log_i("Opening network for joining for %d seconds", 180); - esp_zb_bdb_open_network(180); - } - } else { - log_e("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); - } - break; - case ESP_ZB_BDB_SIGNAL_FORMATION: - if (err_status == ESP_OK) { - esp_zb_ieee_addr_t extended_pan_id; - esp_zb_get_extended_pan_id(extended_pan_id); - log_i( - "Formed network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", - 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(), esp_zb_get_short_address() - ); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); - } else { - log_i("Restart network formation (status: %s)", 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_FORMATION, 1000); - } - break; - case ESP_ZB_BDB_SIGNAL_STEERING: - if (err_status == ESP_OK) { - log_i("Network steering started"); - } - break; - case ESP_ZB_ZDO_SIGNAL_DEVICE_ANNCE: - dev_annce_params = (esp_zb_zdo_signal_device_annce_params_t *)esp_zb_app_signal_get_params(p_sg_p); - log_i("New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr); - esp_zb_zdo_match_desc_req_param_t cmd_req; - cmd_req.dst_nwk_addr = dev_annce_params->device_short_addr; - cmd_req.addr_of_interest = dev_annce_params->device_short_addr; - esp_zb_zdo_find_on_off_light(&cmd_req, user_find_cb, NULL); - break; - case ESP_ZB_NWK_SIGNAL_PERMIT_JOIN_STATUS: - if (err_status == ESP_OK) { - if (*(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)) { - log_i("Network(0x%04hx) is open for %d seconds", esp_zb_get_pan_id(), *(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)); - } else { - log_w("Network(0x%04hx) closed, devices joining not allowed.", esp_zb_get_pan_id()); - } - } - break; - default: log_i("ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); break; - } -} - -static void esp_zb_task(void *pvParameters) { - esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZC_CONFIG(); - esp_zb_init(&zb_nwk_cfg); - esp_zb_on_off_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_ON_OFF_SWITCH_CONFIG(); - esp_zb_ep_list_t *esp_zb_on_off_switch_ep = esp_zb_on_off_switch_ep_create(HA_ONOFF_SWITCH_ENDPOINT, &switch_cfg); - esp_zb_device_register(esp_zb_on_off_switch_ep); - esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK); - ESP_ERROR_CHECK(esp_zb_start(false)); - esp_zb_main_loop_iteration(); -} - -/********************* GPIO functions **************************/ -static QueueHandle_t gpio_evt_queue = NULL; - -static void IRAM_ATTR gpio_isr_handler(void *arg) { - xQueueSendFromISR(gpio_evt_queue, (switch_func_pair_t *)arg, NULL); -} - -static void switch_gpios_intr_enabled(bool enabled) { - for (int i = 0; i < PAIR_SIZE(button_func_pair); ++i) { - if (enabled) { - enableInterrupt((button_func_pair[i]).pin); - } else { - disableInterrupt((button_func_pair[i]).pin); - } - } -} - -/********************* Arduino functions **************************/ -void setup() { - // Init Zigbee - 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)); - - // Init button switch - for (int i = 0; i < PAIR_SIZE(button_func_pair); i++) { - pinMode(button_func_pair[i].pin, INPUT_PULLUP); - /* create a queue to handle gpio event from isr */ - gpio_evt_queue = xQueueCreate(10, sizeof(switch_func_pair_t)); - if (gpio_evt_queue == 0) { - log_e("Queue was not created and must not be used"); - while (1); - } - attachInterruptArg(button_func_pair[i].pin, gpio_isr_handler, (void *)(button_func_pair + i), FALLING); - } - - // Start Zigbee task - xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL); -} - -void loop() { - // Handle button switch in loop() - uint8_t pin = 0; - switch_func_pair_t button_func_pair; - static switch_state_t switch_state = SWITCH_IDLE; - bool evt_flag = false; - - /* check if there is any queue received, if yes read out the button_func_pair */ - if (xQueueReceive(gpio_evt_queue, &button_func_pair, portMAX_DELAY)) { - pin = button_func_pair.pin; - switch_gpios_intr_enabled(false); - evt_flag = true; - } - while (evt_flag) { - bool value = digitalRead(pin); - switch (switch_state) { - case SWITCH_IDLE: switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE; break; - case SWITCH_PRESS_DETECTED: switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED; break; - case SWITCH_RELEASE_DETECTED: - switch_state = SWITCH_IDLE; - /* callback to button_handler */ - (*esp_zb_buttons_handler)(&button_func_pair); - break; - default: break; - } - if (switch_state == SWITCH_IDLE) { - switch_gpios_intr_enabled(true); - evt_flag = false; - break; - } - vTaskDelay(10 / portTICK_PERIOD_MS); - } -} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/ci.json b/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/ci.json deleted file mode 100644 index 7cfaa76784d..00000000000 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/ci.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } -} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino b/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino deleted file mode 100644 index a510c968051..00000000000 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright 2024 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @brief This example demonstrates simple Zigbee temperature sensor. - * - * The example demonstrates how to use ESP Zigbee stack to create a end device temperature sensor. - * The temperature sensor is a Zigbee end device, which is controlled by a Zigbee coordinator. - * - * Proper Zigbee mode must be selected in Tools->Zigbee mode - * and also the correct partition scheme must be selected in Tools->Partition Scheme. - * - * Please check the README.md for instructions and more detailed description. - */ - -#ifndef ZIGBEE_MODE_ED -#error "Zigbee end device mode is not selected in Tools->Zigbee mode" -#endif - -#include "esp_zigbee_core.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "ha/esp_zigbee_ha_standard.h" - -/* Switch configuration */ -#define GPIO_INPUT_IO_TOGGLE_SWITCH GPIO_NUM_9 -#define PAIR_SIZE(TYPE_STR_PAIR) (sizeof(TYPE_STR_PAIR) / sizeof(TYPE_STR_PAIR[0])) - -typedef enum { - SWITCH_ON_CONTROL, - SWITCH_OFF_CONTROL, - SWITCH_ONOFF_TOGGLE_CONTROL, - SWITCH_LEVEL_UP_CONTROL, - SWITCH_LEVEL_DOWN_CONTROL, - SWITCH_LEVEL_CYCLE_CONTROL, - SWITCH_COLOR_CONTROL, -} switch_func_t; - -typedef struct { - uint8_t pin; - switch_func_t func; -} switch_func_pair_t; - -typedef enum { - SWITCH_IDLE, - SWITCH_PRESS_ARMED, - SWITCH_PRESS_DETECTED, - SWITCH_PRESSED, - SWITCH_RELEASE_DETECTED, -} switch_state_t; - -static switch_func_pair_t button_func_pair[] = {{GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL}}; - -/* Default End Device config */ -#define ESP_ZB_ZED_CONFIG() \ - { \ - .esp_zb_role = ESP_ZB_DEVICE_TYPE_ED, .install_code_policy = INSTALLCODE_POLICY_ENABLE, \ - .nwk_cfg = { \ - .zed_cfg = \ - { \ - .ed_timeout = ED_AGING_TIMEOUT, \ - .keep_alive = ED_KEEP_ALIVE, \ - }, \ - }, \ - } - -#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, } - -/* Zigbee configuration */ -#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ -#define ED_AGING_TIMEOUT ESP_ZB_ED_AGING_TIMEOUT_64MIN -#define ED_KEEP_ALIVE 3000 /* 3000 millisecond */ -#define HA_ESP_SENSOR_ENDPOINT 10 /* esp temperature sensor device endpoint, used for temperature measurement */ -#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ - -/* Temperature sensor configuration */ -#define ESP_TEMP_SENSOR_UPDATE_INTERVAL (1) /* Local sensor update interval (second) */ -#define ESP_TEMP_SENSOR_MIN_VALUE (10) /* Local sensor min measured value (degree Celsius) */ -#define ESP_TEMP_SENSOR_MAX_VALUE (50) /* Local sensor max measured value (degree Celsius) */ - -/* Attribute values in ZCL string format - * The string should be started with the length of its own. - */ -#define MANUFACTURER_NAME \ - "\x0B" \ - "ESPRESSIF" -#define MODEL_IDENTIFIER "\x09" CONFIG_IDF_TARGET - -/********************* Zigbee functions **************************/ -static int16_t zb_temperature_to_s16(float temp) { - return (int16_t)(temp * 100); -} - -static void esp_zb_buttons_handler(switch_func_pair_t *button_func_pair) { - if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) { - /* Send report attributes command */ - esp_zb_zcl_report_attr_cmd_t report_attr_cmd; - report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; - report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID; - report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE; - report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; - report_attr_cmd.zcl_basic_cmd.src_endpoint = HA_ESP_SENSOR_ENDPOINT; - - esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); - esp_zb_lock_release(); - log_i("Send 'report attributes' command"); - } -} - -static void esp_app_temp_sensor_handler(float temperature) { - int16_t measured_value = zb_temperature_to_s16(temperature); - Serial.println("Updating temperature sensor value..."); - Serial.println(measured_value); - /* Update temperature sensor measured value */ - esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_set_attribute_val( - HA_ESP_SENSOR_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &measured_value, - false - ); - esp_zb_lock_release(); -} - -static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) { - ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); -} - -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 = (esp_zb_app_signal_type_t)*p_sg_p; - switch (sig_type) { - case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: - log_i("Zigbee stack initialized"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION); - break; - case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: - case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: - if (err_status == ESP_OK) { - log_i("Start network steering"); - log_i("Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non"); - // Start Temperature sensor reading task - xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); - if (esp_zb_bdb_is_factory_new()) { - log_i("Start network steering"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); - } else { - log_i("Device rebooted"); - } - } else { - /* commissioning failed */ - log_w("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); - } - break; - case ESP_ZB_BDB_SIGNAL_STEERING: - if (err_status == ESP_OK) { - esp_zb_ieee_addr_t extended_pan_id; - esp_zb_get_extended_pan_id(extended_pan_id); - log_i( - "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", - 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(), esp_zb_get_short_address() - ); - } else { - log_i("Network steering was not successful (status: %s)", 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); - } - break; - default: log_i("ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); break; - } -} - -static esp_zb_cluster_list_t *custom_temperature_sensor_clusters_create(esp_zb_temperature_sensor_cfg_t *temperature_sensor) { - esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); - esp_zb_attribute_list_t *basic_cluster = esp_zb_basic_cluster_create(&(temperature_sensor->basic_cfg)); - ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)MANUFACTURER_NAME)); - ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)MODEL_IDENTIFIER)); - ESP_ERROR_CHECK(esp_zb_cluster_list_add_basic_cluster(cluster_list, basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE)); - ESP_ERROR_CHECK( - esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(&(temperature_sensor->identify_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE) - ); - ESP_ERROR_CHECK( - esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE) - ); - ESP_ERROR_CHECK(esp_zb_cluster_list_add_temperature_meas_cluster( - cluster_list, esp_zb_temperature_meas_cluster_create(&(temperature_sensor->temp_meas_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE - )); - return cluster_list; -} - -static esp_zb_ep_list_t *custom_temperature_sensor_ep_create(uint8_t endpoint_id, esp_zb_temperature_sensor_cfg_t *temperature_sensor) { - esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create(); - esp_zb_endpoint_config_t endpoint_config = { - .endpoint = endpoint_id, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID, .app_device_version = 0 - }; - esp_zb_ep_list_add_ep(ep_list, custom_temperature_sensor_clusters_create(temperature_sensor), endpoint_config); - return ep_list; -} - -static void esp_zb_task(void *pvParameters) { - esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG(); - esp_zb_init(&zb_nwk_cfg); - /* Create customized temperature sensor endpoint */ - esp_zb_temperature_sensor_cfg_t sensor_cfg = ESP_ZB_DEFAULT_TEMPERATURE_SENSOR_CONFIG(); - /* Set (Min|Max)MeasuredValure */ - sensor_cfg.temp_meas_cfg.min_value = zb_temperature_to_s16(ESP_TEMP_SENSOR_MIN_VALUE); - sensor_cfg.temp_meas_cfg.max_value = zb_temperature_to_s16(ESP_TEMP_SENSOR_MAX_VALUE); - esp_zb_ep_list_t *esp_zb_sensor_ep = custom_temperature_sensor_ep_create(HA_ESP_SENSOR_ENDPOINT, &sensor_cfg); - /* Register the device */ - esp_zb_device_register(esp_zb_sensor_ep); - - /* Config the reporting info */ - esp_zb_zcl_reporting_info_t reporting_info = { - .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV, - .ep = HA_ESP_SENSOR_ENDPOINT, - .cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, - .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, - .attr_id = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, - .u = - { - .send_info = - { - .min_interval = 1, - .max_interval = 0, - .delta = - { - .u16 = 100, - }, - .def_min_interval = 1, - .def_max_interval = 0, - }, - }, - .dst = - { - .profile_id = ESP_ZB_AF_HA_PROFILE_ID, - }, - .manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC, - }; - esp_zb_zcl_update_reporting_info(&reporting_info); - esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK); - - //Erase NVRAM before creating connection to new Coordinator - //esp_zb_nvram_erase_at_start(true); //Comment out this line to erase NVRAM data if you are connecting to new Coordinator - - ESP_ERROR_CHECK(esp_zb_start(false)); - esp_zb_main_loop_iteration(); -} - -/********************* GPIO functions **************************/ -static QueueHandle_t gpio_evt_queue = NULL; - -static void IRAM_ATTR gpio_isr_handler(void *arg) { - xQueueSendFromISR(gpio_evt_queue, (switch_func_pair_t *)arg, NULL); -} - -static void switch_gpios_intr_enabled(bool enabled) { - for (int i = 0; i < PAIR_SIZE(button_func_pair); ++i) { - if (enabled) { - enableInterrupt((button_func_pair[i]).pin); - } else { - disableInterrupt((button_func_pair[i]).pin); - } - } -} - -/************************ Temp sensor *****************************/ -static void temp_sensor_value_update(void *arg) { - for (;;) { - float tsens_value = temperatureRead(); - esp_app_temp_sensor_handler(tsens_value); - delay(1000); - } -} - -/********************* Arduino functions **************************/ -void setup() { - Serial.begin(115200); - // Init Zigbee - 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)); - - // Init button switch - for (int i = 0; i < PAIR_SIZE(button_func_pair); i++) { - pinMode(button_func_pair[i].pin, INPUT_PULLUP); - /* create a queue to handle gpio event from isr */ - gpio_evt_queue = xQueueCreate(10, sizeof(switch_func_pair_t)); - if (gpio_evt_queue == 0) { - log_e("Queue was not created and must not be used"); - while (1); - } - attachInterruptArg(button_func_pair[i].pin, gpio_isr_handler, (void *)(button_func_pair + i), FALLING); - } - - // Start Zigbee task - xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL); -} - -void loop() { - // Handle button switch in loop() - uint8_t pin = 0; - switch_func_pair_t button_func_pair; - static switch_state_t switch_state = SWITCH_IDLE; - bool evt_flag = false; - float temperature; - - /* check if there is any queue received, if yes read out the button_func_pair */ - if (xQueueReceive(gpio_evt_queue, &button_func_pair, portMAX_DELAY)) { - pin = button_func_pair.pin; - switch_gpios_intr_enabled(false); - evt_flag = true; - } - while (evt_flag) { - bool value = digitalRead(pin); - switch (switch_state) { - case SWITCH_IDLE: switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE; break; - case SWITCH_PRESS_DETECTED: switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED; break; - case SWITCH_RELEASE_DETECTED: - switch_state = SWITCH_IDLE; - /* callback to button_handler */ - (*esp_zb_buttons_handler)(&button_func_pair); - break; - default: break; - } - if (switch_state == SWITCH_IDLE) { - switch_gpios_intr_enabled(true); - evt_flag = false; - break; - } - delay(10); - } -} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/ci.json b/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/ci.json deleted file mode 100644 index 7cfaa76784d..00000000000 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/ci.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } -} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/Zigbee_Thermostat.ino b/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/Zigbee_Thermostat.ino deleted file mode 100644 index f229b9f10e8..00000000000 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/Zigbee_Thermostat.ino +++ /dev/null @@ -1,565 +0,0 @@ -// Copyright 2024 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @brief This example demonstrates simple Zigbee thermostat. - * - * The example demonstrates how to use ESP Zigbee stack to get data from temperature - * sensor end device and act as an thermostat. - * The temperature sensor is a Zigbee end device, which is controlled by a Zigbee coordinator (thermostat). - * Button switch and Zigbee runs in separate tasks. - * - * Proper Zigbee mode must be selected in Tools->Zigbee mode - * and also the correct partition scheme must be selected in Tools->Partition Scheme. - * - * Please check the README.md for instructions and more detailed description. - */ - -#ifndef ZIGBEE_MODE_ZCZR -#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" -#endif - -#include "esp_zigbee_core.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "ha/esp_zigbee_ha_standard.h" - -#define ARRAY_LENTH(arr) (sizeof(arr) / sizeof(arr[0])) - -/* Switch configuration */ -#define GPIO_INPUT_IO_TOGGLE_SWITCH GPIO_NUM_9 -#define PAIR_SIZE(TYPE_STR_PAIR) (sizeof(TYPE_STR_PAIR) / sizeof(TYPE_STR_PAIR[0])) - -typedef enum { - SWITCH_ON_CONTROL, - SWITCH_OFF_CONTROL, - SWITCH_ONOFF_TOGGLE_CONTROL, - SWITCH_LEVEL_UP_CONTROL, - SWITCH_LEVEL_DOWN_CONTROL, - SWITCH_LEVEL_CYCLE_CONTROL, - SWITCH_COLOR_CONTROL, -} switch_func_t; - -typedef struct { - uint8_t pin; - switch_func_t func; -} switch_func_pair_t; - -typedef enum { - SWITCH_IDLE, - SWITCH_PRESS_ARMED, - SWITCH_PRESS_DETECTED, - SWITCH_PRESSED, - SWITCH_RELEASE_DETECTED, -} switch_state_t; - -static switch_func_pair_t button_func_pair[] = {{GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL}}; - -/* Default Coordinator config */ -#define ESP_ZB_ZC_CONFIG() \ - { \ - .esp_zb_role = ESP_ZB_DEVICE_TYPE_COORDINATOR, .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, } - -/* Temperature sensor device parameters */ -typedef struct temp_sensor_device_params_s { - esp_zb_ieee_addr_t ieee_addr; - uint8_t endpoint; - uint16_t short_addr; -} temp_sensor_device_params_t; - -typedef struct zbstring_s { - uint8_t len; - char data[]; -} ESP_ZB_PACKED_STRUCT zbstring_t; - -static temp_sensor_device_params_t temp_sensor; - -/* Zigbee configuration */ -#define MAX_CHILDREN 10 /* the max amount of connected devices */ -#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ -#define HA_THERMOSTAT_ENDPOINT 1 /* esp light switch device endpoint */ -#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ - -/* Attribute values in ZCL string format - * The string should be started with the length of its own. - */ -#define MANUFACTURER_NAME \ - "\x0B" \ - "ESPRESSIF" -#define MODEL_IDENTIFIER "\x09" CONFIG_IDF_TARGET - -/********************* Zigbee functions **************************/ -static float zb_s16_to_temperature(int16_t value) { - return 1.0 * value / 100; -} - -static void esp_zb_buttons_handler(switch_func_pair_t *button_func_pair) { - if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) { - /* Send "read attributes" command to the bound sensor */ - esp_zb_zcl_read_attr_cmd_t read_req; - read_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; - read_req.zcl_basic_cmd.src_endpoint = HA_THERMOSTAT_ENDPOINT; - read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; - - uint16_t attributes[] = { - ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, - ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID - }; - read_req.attr_number = ARRAY_LENTH(attributes); - read_req.attr_field = attributes; - - /* Send "configure report attribute" command to the bound sensor */ - esp_zb_zcl_config_report_cmd_t report_cmd; - report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; - report_cmd.zcl_basic_cmd.src_endpoint = HA_THERMOSTAT_ENDPOINT; - report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; - - int16_t report_change = 200; /* report on each 2 degree changes */ - esp_zb_zcl_config_report_record_t records[] = { - { - .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV, - .attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, - .attrType = ESP_ZB_ZCL_ATTR_TYPE_S16, - .min_interval = 0, - .max_interval = 10, - .reportable_change = &report_change, - }, - }; - report_cmd.record_number = ARRAY_LENTH(records); - report_cmd.record_field = records; - - esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_config_report_cmd_req(&report_cmd); - esp_zb_lock_release(); - log_i("Send 'configure reporting' command"); - - esp_zb_lock_acquire(portMAX_DELAY); - esp_zb_zcl_read_attr_cmd_req(&read_req); - esp_zb_lock_release(); - log_i("Send 'read attributes' command"); - } -} - -static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) { - ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); -} - -static void bind_cb(esp_zb_zdp_status_t zdo_status, void *user_ctx) { - esp_zb_zdo_bind_req_param_t *bind_req = (esp_zb_zdo_bind_req_param_t *)user_ctx; - - if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { - /* Local binding succeeds */ - if (bind_req->req_dst_addr == esp_zb_get_short_address()) { - log_i("Successfully bind the temperature sensor from address(0x%x) on endpoint(%d)", temp_sensor.short_addr, temp_sensor.endpoint); - - /* Read peer Manufacture Name & Model Identifier */ - esp_zb_zcl_read_attr_cmd_t read_req; - read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; - read_req.zcl_basic_cmd.src_endpoint = HA_THERMOSTAT_ENDPOINT; - read_req.zcl_basic_cmd.dst_endpoint = temp_sensor.endpoint; - read_req.zcl_basic_cmd.dst_addr_u.addr_short = temp_sensor.short_addr; - read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC; - - uint16_t attributes[] = { - ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, - ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, - }; - read_req.attr_number = ARRAY_LENTH(attributes); - read_req.attr_field = attributes; - - esp_zb_zcl_read_attr_cmd_req(&read_req); - } - if (bind_req->req_dst_addr == temp_sensor.short_addr) { - log_i("The temperature sensor from address(0x%x) on endpoint(%d) successfully binds us", temp_sensor.short_addr, temp_sensor.endpoint); - } - free(bind_req); - } else { - /* Bind failed, maybe retry the binding ? */ - - // esp_zb_zdo_device_bind_req(bind_req, bind_cb, bind_req); - } -} - -static void user_find_cb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { - if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { - log_i("Found temperature sensor"); - /* Store the information of the remote device */ - temp_sensor_device_params_t *sensor = (temp_sensor_device_params_t *)user_ctx; - sensor->endpoint = endpoint; - sensor->short_addr = addr; - esp_zb_ieee_address_by_short(sensor->short_addr, sensor->ieee_addr); - log_d("Temperature sensor found: short address(0x%x), endpoint(%d)", sensor->short_addr, sensor->endpoint); - - /* 1. Send binding request to the sensor */ - esp_zb_zdo_bind_req_param_t *bind_req = (esp_zb_zdo_bind_req_param_t *)calloc(sizeof(esp_zb_zdo_bind_req_param_t), 1); - bind_req->req_dst_addr = addr; - log_d("Request temperature sensor to bind us"); - - /* populate the src information of the binding */ - memcpy(bind_req->src_address, sensor->ieee_addr, sizeof(esp_zb_ieee_addr_t)); - bind_req->src_endp = endpoint; - bind_req->cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; - log_d("Bind temperature sensor"); - - /* populate the dst information of the binding */ - bind_req->dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; - esp_zb_get_long_address(bind_req->dst_address_u.addr_long); - bind_req->dst_endp = HA_THERMOSTAT_ENDPOINT; - - log_i("Request temperature sensor to bind us"); - esp_zb_zdo_device_bind_req(bind_req, bind_cb, bind_req); - - /* 2. Send binding request to self */ - bind_req = (esp_zb_zdo_bind_req_param_t *)calloc(sizeof(esp_zb_zdo_bind_req_param_t), 1); - bind_req->req_dst_addr = esp_zb_get_short_address(); - - /* populate the src information of the binding */ - esp_zb_get_long_address(bind_req->src_address); - bind_req->src_endp = HA_THERMOSTAT_ENDPOINT; - bind_req->cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; - - /* populate the dst information of the binding */ - bind_req->dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; - memcpy(bind_req->dst_address_u.addr_long, sensor->ieee_addr, sizeof(esp_zb_ieee_addr_t)); - bind_req->dst_endp = endpoint; - - log_i("Bind temperature sensor"); - esp_zb_zdo_device_bind_req(bind_req, bind_cb, bind_req); - } -} - -static void find_temperature_sensor(esp_zb_zdo_match_desc_req_param_t *param, esp_zb_zdo_match_desc_callback_t user_cb, void *user_ctx) { - uint16_t cluster_list[] = {ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT}; - param->profile_id = ESP_ZB_AF_HA_PROFILE_ID; - param->num_in_clusters = 1; - param->num_out_clusters = 0; - param->cluster_list = cluster_list; - esp_zb_zdo_match_cluster(param, user_cb, (void *)&temp_sensor); -} - -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 = (esp_zb_app_signal_type_t)*p_sg_p; - esp_zb_zdo_signal_device_annce_params_t *dev_annce_params = NULL; - switch (sig_type) { - case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: - log_i("Zigbee stack initialized"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION); - break; - case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: - case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: - if (err_status == ESP_OK) { - log_i("Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non"); - if (esp_zb_bdb_is_factory_new()) { - log_i("Start network formation"); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); - } else { - log_i("Device rebooted"); - log_i("Opening network for joining for %d seconds", 180); - esp_zb_bdb_open_network(180); - } - } else { - log_e("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); - } - break; - case ESP_ZB_BDB_SIGNAL_FORMATION: - if (err_status == ESP_OK) { - esp_zb_ieee_addr_t extended_pan_id; - esp_zb_get_extended_pan_id(extended_pan_id); - log_i( - "Formed network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", - 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(), esp_zb_get_short_address() - ); - esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); - } else { - log_i("Restart network formation (status: %s)", 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_FORMATION, 1000); - } - break; - case ESP_ZB_BDB_SIGNAL_STEERING: - if (err_status == ESP_OK) { - log_i("Network steering started"); - } - break; - case ESP_ZB_ZDO_SIGNAL_DEVICE_ANNCE: - dev_annce_params = (esp_zb_zdo_signal_device_annce_params_t *)esp_zb_app_signal_get_params(p_sg_p); - log_i("New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr); - esp_zb_zdo_match_desc_req_param_t cmd_req; - cmd_req.dst_nwk_addr = dev_annce_params->device_short_addr; - cmd_req.addr_of_interest = dev_annce_params->device_short_addr; - find_temperature_sensor(&cmd_req, user_find_cb, NULL); - break; - case ESP_ZB_NWK_SIGNAL_PERMIT_JOIN_STATUS: - if (err_status == ESP_OK) { - if (*(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)) { - log_i("Network(0x%04hx) is open for %d seconds", esp_zb_get_pan_id(), *(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)); - } else { - log_w("Network(0x%04hx) closed, devices joining not allowed.", esp_zb_get_pan_id()); - } - } - break; - default: log_i("ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); break; - } -} - -static void esp_app_zb_attribute_handler(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) { - /* Basic cluster attributes */ - if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_BASIC) { - if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) { - zbstring_t *zbstr = (zbstring_t *)attribute->data.value; - char *string = (char *)malloc(zbstr->len + 1); - memcpy(string, zbstr->data, zbstr->len); - string[zbstr->len] = '\0'; - log_i("Peer Manufacturer is \"%s\"", string); - free(string); - } - if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) { - zbstring_t *zbstr = (zbstring_t *)attribute->data.value; - char *string = (char *)malloc(zbstr->len + 1); - memcpy(string, zbstr->data, zbstr->len); - string[zbstr->len] = '\0'; - log_i("Peer Model is \"%s\"", string); - free(string); - } - } - - /* Temperature Measurement cluster attributes */ - if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT) { - if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { - int16_t value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; - log_i("Measured Value is %.2f degrees Celsius", zb_s16_to_temperature(value)); - } - if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { - int16_t min_value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; - log_i("Min Measured Value is %.2f degrees Celsius", zb_s16_to_temperature(min_value)); - } - if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { - int16_t max_value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; - log_i("Max Measured Value is %.2f degrees Celsius", zb_s16_to_temperature(max_value)); - } - if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) { - uint16_t tolerance = attribute->data.value ? *(uint16_t *)attribute->data.value : 0; - log_i("Tolerance is %.2f degrees Celsius", 1.0 * tolerance / 100); - } - } -} - -static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_message_t *message) { - if (!message) { - log_e("Empty message"); - } - if (message->status != ESP_ZB_ZCL_STATUS_SUCCESS) { - log_e("Received message: error status(%d)", message->status); - } - log_i( - "Received report from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->src_address.u.short_addr, message->src_endpoint, - message->dst_endpoint, message->cluster - ); - esp_app_zb_attribute_handler(message->cluster, &message->attribute); - return ESP_OK; -} - -static esp_err_t zb_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message) { - if (!message) { - log_e("Empty message"); - } - if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) { - log_e("Received message: error status(%d)", message->info.status); - } - log_i( - "Read attribute response: from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->info.src_address.u.short_addr, - message->info.src_endpoint, message->info.dst_endpoint, message->info.cluster - ); - - esp_zb_zcl_read_attr_resp_variable_t *variable = message->variables; - while (variable) { - log_i( - "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 (variable->status == ESP_ZB_ZCL_STATUS_SUCCESS) { - esp_app_zb_attribute_handler(message->info.cluster, &variable->attribute); - } - - variable = variable->next; - } - - return ESP_OK; -} - -static esp_err_t zb_configure_report_resp_handler(const esp_zb_zcl_cmd_config_report_resp_message_t *message) { - if (!message) { - log_e("Empty message"); - } - if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) { - log_e("Received message: error status(%d)", message->info.status); - } - esp_zb_zcl_config_report_resp_variable_t *variable = message->variables; - while (variable) { - log_i( - "Configure report response: status(%d), cluster(0x%x), direction(0x%x), attribute(0x%x)", variable->status, message->info.cluster, variable->direction, - variable->attribute_id - ); - variable = variable->next; - } - - return ESP_OK; -} - -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_REPORT_ATTR_CB_ID: ret = zb_attribute_reporting_handler((esp_zb_zcl_report_attr_message_t *)message); 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); break; - case ESP_ZB_CORE_CMD_REPORT_CONFIG_RESP_CB_ID: ret = zb_configure_report_resp_handler((esp_zb_zcl_cmd_config_report_resp_message_t *)message); break; - default: log_w("Receive Zigbee action(0x%x) callback", callback_id); break; - } - return ret; -} - -static esp_zb_cluster_list_t *custom_thermostat_clusters_create(esp_zb_thermostat_cfg_t *thermostat) { - esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); - esp_zb_attribute_list_t *basic_cluster = esp_zb_basic_cluster_create(&(thermostat->basic_cfg)); - ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)MANUFACTURER_NAME)); - ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)MODEL_IDENTIFIER)); - ESP_ERROR_CHECK(esp_zb_cluster_list_add_basic_cluster(cluster_list, basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE)); - ESP_ERROR_CHECK( - esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(&(thermostat->identify_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE) - ); - ESP_ERROR_CHECK( - esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE) - ); - ESP_ERROR_CHECK( - esp_zb_cluster_list_add_thermostat_cluster(cluster_list, esp_zb_thermostat_cluster_create(&(thermostat->thermostat_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE) - ); - /* Add temperature measurement cluster for attribute reporting */ - ESP_ERROR_CHECK(esp_zb_cluster_list_add_temperature_meas_cluster(cluster_list, esp_zb_temperature_meas_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE)); - return cluster_list; -} - -static esp_zb_ep_list_t *custom_thermostat_ep_create(uint8_t endpoint_id, esp_zb_thermostat_cfg_t *thermostat) { - esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create(); - esp_zb_endpoint_config_t endpoint_config = { - .endpoint = endpoint_id, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_THERMOSTAT_DEVICE_ID, .app_device_version = 0 - }; - esp_zb_ep_list_add_ep(ep_list, custom_thermostat_clusters_create(thermostat), endpoint_config); - return ep_list; -} - -static void esp_zb_task(void *pvParameters) { - /* Initialize Zigbee stack */ - esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZC_CONFIG(); - esp_zb_init(&zb_nwk_cfg); - /* Create customized thermostat endpoint */ - esp_zb_thermostat_cfg_t thermostat_cfg = ESP_ZB_DEFAULT_THERMOSTAT_CONFIG(); - esp_zb_ep_list_t *esp_zb_thermostat_ep = custom_thermostat_ep_create(HA_THERMOSTAT_ENDPOINT, &thermostat_cfg); - /* Register the device */ - esp_zb_device_register(esp_zb_thermostat_ep); - - esp_zb_core_action_handler_register(zb_action_handler); - esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK); - ESP_ERROR_CHECK(esp_zb_start(false)); - esp_zb_main_loop_iteration(); -} - -/********************* GPIO functions **************************/ -static QueueHandle_t gpio_evt_queue = NULL; - -static void IRAM_ATTR gpio_isr_handler(void *arg) { - xQueueSendFromISR(gpio_evt_queue, (switch_func_pair_t *)arg, NULL); -} - -static void switch_gpios_intr_enabled(bool enabled) { - for (int i = 0; i < PAIR_SIZE(button_func_pair); ++i) { - if (enabled) { - enableInterrupt((button_func_pair[i]).pin); - } else { - disableInterrupt((button_func_pair[i]).pin); - } - } -} - -/********************* Arduino functions **************************/ -void setup() { - // Init Zigbee - 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)); - - // Init button switch - for (int i = 0; i < PAIR_SIZE(button_func_pair); i++) { - pinMode(button_func_pair[i].pin, INPUT_PULLUP); - /* create a queue to handle gpio event from isr */ - gpio_evt_queue = xQueueCreate(10, sizeof(switch_func_pair_t)); - if (gpio_evt_queue == 0) { - log_e("Queue was not created and must not be used"); - while (1); - } - attachInterruptArg(button_func_pair[i].pin, gpio_isr_handler, (void *)(button_func_pair + i), FALLING); - } - - // Start Zigbee task - xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL); -} - -void loop() { - // Handle button switch in loop() - uint8_t pin = 0; - switch_func_pair_t button_func_pair; - static switch_state_t switch_state = SWITCH_IDLE; - bool evt_flag = false; - - /* check if there is any queue received, if yes read out the button_func_pair */ - if (xQueueReceive(gpio_evt_queue, &button_func_pair, portMAX_DELAY)) { - pin = button_func_pair.pin; - switch_gpios_intr_enabled(false); - evt_flag = true; - } - while (evt_flag) { - bool value = digitalRead(pin); - switch (switch_state) { - case SWITCH_IDLE: switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE; break; - case SWITCH_PRESS_DETECTED: switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED; break; - case SWITCH_RELEASE_DETECTED: - switch_state = SWITCH_IDLE; - /* callback to button_handler */ - (*esp_zb_buttons_handler)(&button_func_pair); - break; - default: break; - } - if (switch_state == SWITCH_IDLE) { - switch_gpios_intr_enabled(true); - evt_flag = false; - break; - } - delay(10); - } -} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/ci.json b/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/ci.json deleted file mode 100644 index 7cfaa76784d..00000000000 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/ci.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "targets": { - "esp32": false, - "esp32c3": false, - "esp32c6": false, - "esp32h2": false, - "esp32s2": false, - "esp32s3": false - } -} diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/README.md b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/README.md new file mode 100644 index 00000000000..4da23c8c7d2 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/README.md @@ -0,0 +1,68 @@ +# Arduino-ESP32 Zigbee Color Dimmable Light Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) color dimmable light. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with Zigbee_Color_Dimmer_Switch example) +* A USB cable for power supply and programming +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the Zigbee_Color_Dimmable_Light example + +### Configure the Project + +Set the LED GPIO by changing the `LED_PIN` definition. By default, the LED_PIN is `RGB_BUILTIN`. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino new file mode 100644 index 00000000000..1ce9ff56816 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino @@ -0,0 +1,104 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee Color Dimmable light bulb. + * + * The example demonstrates how to use Zigbee library to create an end device with + * color dimmable light end point. + * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "ZigbeeCore.h" +#include "ep/ZigbeeColorDimmableLight.h" + +#define LED_PIN RGB_BUILTIN +#define BUTTON_PIN 9 // C6/H2 Boot button +#define ZIGBEE_LIGHT_ENDPOINT 10 + +ZigbeeColorDimmableLight zbColorLight = ZigbeeColorDimmableLight(ZIGBEE_LIGHT_ENDPOINT); + +/********************* RGB LED functions **************************/ +void setRGBLight(bool state, uint8_t red, uint8_t green, uint8_t blue, uint8_t level) { + float brightness = (float)level / 255; + rgbLedWrite(LED_PIN, red * brightness, green * brightness, blue * brightness); +} + +// Create a task on identify call to handle the identify function +void identify(uint16_t time) { + static uint8_t blink = 1; + log_d("Identify called for %d seconds", time); + if (time == 0) { + // If identify time is 0, stop blinking and restore light as it was used for identify + zbColorLight.restoreLight(); + return; + } + rgbLedWrite(LED_PIN, 255 * blink, 255 * blink, 255 * blink); + blink = !blink; +} + +/********************* Arduino functions **************************/ +void setup() { + // Init RMT and leave light OFF + rgbLedWrite(LED_PIN, 0, 0, 0); + + // Init button for factory reset + pinMode(BUTTON_PIN, INPUT); + + // Set callback function for light change + zbColorLight.onLightChange(setRGBLight); + + // Optional: Set callback function for device identify + zbColorLight.onIdentify(identify); + + // Optional: Set Zigbee device name and model + zbColorLight.setManufacturerAndModel("Espressif", "ZBColorLightBulb"); + + // Add endpoint to Zigbee Core + log_d("Adding ZigbeeLight endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbColorLight); + + // When all EPs are registered, start Zigbee. By default acts as ZIGBEE_END_DEVICE + log_d("Calling Zigbee.begin()"); + Zigbee.begin(); +} + +void loop() { + // Checking button for factory reset + if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(BUTTON_PIN) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.printf("Resetting Zigbee to factory settings, reboot.\n"); + Zigbee.factoryReset(); + } + } + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json new file mode 100644 index 00000000000..3aaf44eb376 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json @@ -0,0 +1,16 @@ +{ + "fqbn": { + "esp32c6": [ + "espressif:esp32:esp32c6:PartitionScheme=zigbee,ZigbeeMode=ed" + ], + "esp32h2": [ + "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" + ] + }, + "targets": { + "esp32": false, + "esp32c3": false, + "esp32s2": false, + "esp32s3": false + } +} diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/README.md b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/README.md new file mode 100644 index 00000000000..8dd63a78c5e --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/README.md @@ -0,0 +1,68 @@ +# Arduino-ESP32 Zigbee Color Dimmer Switch Example + +This example shows how to configure Zigbee Coordinator and use it as a Home Automation (HA) color dimmer light switch. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee end device (loaded with Zigbee_Color_Dimmable_Light example). +* A USB cable for power supply and programming. +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee coordinator and upload the Zigbee_Color_Dimmable_Light example. + +### Configure the Project + +Set the Button Switch GPIO by changing the `GPIO_SWITCH` definition. By default, it's the pin `9` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the Coordinator Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)`. +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs`. +* Select the COM port: `Tools -> Port: xxx where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with the example `Zigbee_Color_Dimmable_Light` is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino new file mode 100644 index 00000000000..a494623e436 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino @@ -0,0 +1,148 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee color dimmer switch. + * + * The example demonstrates how to use Zigbee library to control a RGB light bulb. + * The RGB light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator (Switch). + * To turn on/off the light, push the button on the switch. + * To change the color or level of the light, send serial commands to the switch. + * + * By setting the switch to allow multiple binding, so it can bind to multiple lights. + * Also every 30 seconds, all bound lights are printed to the serial console. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#include "ZigbeeCore.h" +#include "ep/ZigbeeColorDimmerSwitch.h" + +/* Switch configuration */ +#define SWITCH_PIN 9 // ESP32-C6/H2 Boot button +#define SWITCH_ENDPOINT_NUMBER 5 + +/* Zigbee switch */ +ZigbeeColorDimmerSwitch zbSwitch = ZigbeeColorDimmerSwitch(SWITCH_ENDPOINT_NUMBER); + +/********************* Arduino functions **************************/ +void setup() { + + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + //Init button switch + pinMode(SWITCH_PIN, INPUT); + + //Optional: set Zigbee device name and model + zbSwitch.setManufacturerAndModel("Espressif", "ZigbeeSwitch"); + + //Optional to allow multiple light to bind to the switch + zbSwitch.allowMultipleBinding(true); + + //Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbSwitch); + + //Open network for 180 seconds after boot + Zigbee.setRebootOpenNetwork(180); + + //When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode + Zigbee.begin(ZIGBEE_COORDINATOR); + + Serial.println("Waiting for Light to bound to the switch"); + //Wait for switch to bound to a light: + while (!zbSwitch.isBound()) { + Serial.printf("."); + delay(500); + } + Serial.println(); +} + +void loop() { + // Handle button switch in loop() + if (digitalRead(SWITCH_PIN) == LOW) { // Push button pressed + // Key debounce handling + while (digitalRead(SWITCH_PIN) == LOW) { + delay(50); + } + // Toggle light + zbSwitch.lightToggle(); + } + // Handle serial input to control color and level of the light + if (Serial.available()) { + String command = Serial.readString(); + + if (command == "on") { + zbSwitch.lightOn(); + } else if (command == "off") { + zbSwitch.lightOff(); + } else if (command == "toggle") { + zbSwitch.lightToggle(); + } else if (command == "red") { + zbSwitch.setLightColor(255, 0, 0); + } else if (command == "green") { + zbSwitch.setLightColor(0, 255, 0); + } else if (command == "blue") { + zbSwitch.setLightColor(0, 0, 255); + } else if (command == "white") { + zbSwitch.setLightColor(255, 255, 255); + } else if (command == "color") { + //wait for color value + Serial.println("Enter red value (0-255):"); + while (!Serial.available()) { + delay(100); + } + int red = Serial.parseInt(); + Serial.println("Enter green value (0-255):"); + while (!Serial.available()) { + delay(100); + } + int green = Serial.parseInt(); + Serial.println("Enter blue value (0-255):"); + while (!Serial.available()) { + delay(100); + } + int blue = Serial.parseInt(); + zbSwitch.setLightColor(red, green, blue); + } else if (command == "level") { + //wait for level value + Serial.println("Enter level value (0-255):"); + while (!Serial.available()) { + delay(100); + } + int level = Serial.parseInt(); + zbSwitch.setLightLevel(level); + } else { + Serial.println("Unknown command"); + } + } + + // print the bound devices (lights) every 30 seconds + static uint32_t last_print = 0; + if (millis() - last_print > 30000) { + last_print = millis(); + zbSwitch.printBoundDevices(); + } +} diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json new file mode 100644 index 00000000000..c916121b991 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json @@ -0,0 +1,16 @@ +{ + "fqbn": { + "esp32c6": [ + "espressif:esp32:esp32c6:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" + ], + "esp32h2": [ + "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" + ] + }, + "targets": { + "esp32": false, + "esp32c3": false, + "esp32s2": false, + "esp32s3": false + } +} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/README.md b/libraries/Zigbee/examples/Zigbee_On_Off_Light/README.md similarity index 62% rename from libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/README.md rename to libraries/Zigbee/examples/Zigbee_On_Off_Light/README.md index 807b8a42ade..e74c7505ddb 100644 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Bulb/README.md +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Light/README.md @@ -1,8 +1,6 @@ -# Arduino-ESP32 Zigbee Light Bulb Example +# Arduino-ESP32 Zigbee On/Off Light Example -This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) on/off light bulb. - -**This example is based on ESP-Zigbee-SDK example esp_zigbee_HA_sample/HA_on_off_light.** +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) on/off light. # Supported Targets @@ -13,9 +11,9 @@ Currently, this example supports the following targets. ## Hardware Required -* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with Zigbee_Light_switch example) +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with Zigbee_On_Off_switch example) * A USB cable for power supply and programming -* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device (loaded with Zigbee_Light_bulb example) +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the Zigbee_On_Off_Light example ### Configure the Project @@ -30,17 +28,22 @@ To get more information about the Espressif boards see [Espressif Development Ki * Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` * Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. ## Troubleshooting -If the End device flashed with this example is not connecting to the coordinator, erase the flash before flashing it to the board. It is recommended to do this if you did changes to the coordinator. +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. You can do the following: -* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled` -* In the sketch uncomment function `esp_zb_nvram_erase_at_start(true);` located in `esp_zb_task` function. +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. -By default, the coordinator network is open for 180 s after rebooting or flashing new firmware. After that, the network is closed for adding new devices. -You can change it by editing `esp_zb_bdb_open_network(180);` in `esp_zb_app_signal_handler` function. ***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** @@ -60,14 +63,8 @@ Before creating a new issue, be sure to try Troubleshooting and check if the sam ## Resources -The ESP Zigbee SDK provides more examples: -* ESP Zigbee SDK Docs: [Link](https://docs.espressif.com/projects/esp-zigbee-sdk) -* ESP Zigbee SDK Repo: [Link](https://github.com/espressif/esp-zigbee-sdk) - * Official ESP32 Forum: [Link](https://esp32.com) * Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) -* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) -* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) -* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) -* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) * Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino b/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino new file mode 100644 index 00000000000..2f13357a156 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino @@ -0,0 +1,87 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates simple Zigbee light bulb. + * + * The example demonstrates how to use Zigbee library to create a end device light bulb. + * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "ZigbeeCore.h" +#include "ep/ZigbeeLight.h" + +#define LED_PIN RGB_BUILTIN +#define BUTTON_PIN 9 // ESP32-C6/H2 Boot button +#define ZIGBEE_LIGHT_ENDPOINT 10 + +ZigbeeLight zbLight = ZigbeeLight(ZIGBEE_LIGHT_ENDPOINT); + +/********************* RGB LED functions **************************/ +void setLED(bool value) { + digitalWrite(LED_PIN, value); +} + +/********************* Arduino functions **************************/ +void setup() { + // Init LED and turn it OFF (if LED_PIN == RGB_BUILTIN, the rgbLedWrite() will be used under the hood) + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + // Init button for factory reset + pinMode(BUTTON_PIN, INPUT); + + //Optional: set Zigbee device name and model + zbLight.setManufacturerAndModel("Espressif", "ZBLightBulb"); + + // Set callback function for light change + zbLight.onLightChange(setLED); + + //Add endpoint to Zigbee Core + log_d("Adding ZigbeeLight endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbLight); + + // When all EPs are registered, start Zigbee. By default acts as ZIGBEE_END_DEVICE + log_d("Calling Zigbee.begin()"); + Zigbee.begin(); +} + +void loop() { + // Checking button for factory reset + if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(BUTTON_PIN) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.printf("Resetting Zigbee to factory settings, reboot.\n"); + Zigbee.factoryReset(); + } + } + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json new file mode 100644 index 00000000000..3aaf44eb376 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json @@ -0,0 +1,16 @@ +{ + "fqbn": { + "esp32c6": [ + "espressif:esp32:esp32c6:PartitionScheme=zigbee,ZigbeeMode=ed" + ], + "esp32h2": [ + "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" + ] + }, + "targets": { + "esp32": false, + "esp32c3": false, + "esp32s2": false, + "esp32s3": false + } +} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/README.md b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/README.md similarity index 57% rename from libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/README.md rename to libraries/Zigbee/examples/Zigbee_On_Off_Switch/README.md index efa7d45cb9c..b70f57d6e89 100644 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Light_Switch/README.md +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/README.md @@ -1,9 +1,7 @@ -# Arduino-ESP32 Zigbee Light Switch Example +# Arduino-ESP32 Zigbee On/Off Light Switch Example This example shows how to configure Zigbee Coordinator and use it as a Home Automation (HA) on/off light switch. -**This example is based on ESP-Zigbee-SDK example esp_zigbee_HA_sample/HA_on_off_switch.** - # Supported Targets Currently, this example supports the following targets. @@ -13,34 +11,37 @@ Currently, this example supports the following targets. ## Hardware Required -* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee end device (loaded with Zigbee_Light_bulb example). +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee end device (loaded with Zigbee_On_Off_Light example). * A USB cable for power supply and programming. -* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee coordinator (loaded with Zigbee_Light_switch example). +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee coordinator and upload the Zigbee_On_Off_Switch example. ### Configure the Project -Set the Button Switch GPIO by changing the `GPIO_INPUT_IO_TOGGLE_SWITCH` definition. By default, the LED_PIN is `GPIO_NUM_9`. +Set the Button Switch GPIO by changing the `GPIO_INPUT_IO_TOGGLE_SWITCH` definition. By default, it's the pin `9` (BOOT button on ESP32-C6 and ESP32-H2). #### Using Arduino IDE To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). * Before Compile/Verify, select the correct board: `Tools -> Board`. -* Select the Coordinator Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator)`. +* Select the Coordinator Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)`. * Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs`. * Select the COM port: `Tools -> Port: xxx where the `xxx` is the detected COM port. -* Optional: Set debug level to info to see logs from Zigbee stack: `Tools -> Core Debug Level: Info`. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. ## Troubleshooting -If the End device flashed with the example `Zigbee_Light_Bulb` is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +If the End device flashed with the example `Zigbee_On_Off_Light` is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. You can do the following: * In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. -* In the `Zigbee_Light_Bulb` example sketch uncomment function `esp_zb_nvram_erase_at_start(true);` located in `esp_zb_task` function. +* In the `Zigbee_On_Off_Light` example sketch call `Zigbee.factoryReset();`. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: -By default, the coordinator network is open for 180 s after rebooting or flashing new firmware. After that, the network is closed for adding new devices. -You can change it by editing `esp_zb_bdb_open_network(180);` in `esp_zb_app_signal_handler` function. +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. ***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** @@ -60,14 +61,8 @@ Before creating a new issue, be sure to try Troubleshooting and check if the sam ## Resources -The ESP Zigbee SDK provides more examples: -* ESP Zigbee SDK Docs: [Link](https://docs.espressif.com/projects/esp-zigbee-sdk) -* ESP Zigbee SDK Repo: [Link](https://github.com/espressif/esp-zigbee-sdk) - * Official ESP32 Forum: [Link](https://esp32.com) * Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) -* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) -* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) -* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) -* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) * Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino new file mode 100644 index 00000000000..09487dea05d --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino @@ -0,0 +1,194 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates simple Zigbee light switch. + * + * The example demonstrates how to use Zigbee library to control a light bulb. + * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator (Switch). + * Button switch and Zigbee runs in separate tasks. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#include "ZigbeeCore.h" +#include "ep/ZigbeeSwitch.h" + +#define SWITCH_ENDPOINT_NUMBER 5 + +/* Switch configuration */ +#define GPIO_INPUT_IO_TOGGLE_SWITCH 9 +#define PAIR_SIZE(TYPE_STR_PAIR) (sizeof(TYPE_STR_PAIR) / sizeof(TYPE_STR_PAIR[0])) + +typedef enum { + SWITCH_ON_CONTROL, + SWITCH_OFF_CONTROL, + SWITCH_ONOFF_TOGGLE_CONTROL, + SWITCH_LEVEL_UP_CONTROL, + SWITCH_LEVEL_DOWN_CONTROL, + SWITCH_LEVEL_CYCLE_CONTROL, + SWITCH_COLOR_CONTROL, +} SwitchFunction; + +typedef struct { + uint8_t pin; + SwitchFunction func; +} SwitchData; + +typedef enum { + SWITCH_IDLE, + SWITCH_PRESS_ARMED, + SWITCH_PRESS_DETECTED, + SWITCH_PRESSED, + SWITCH_RELEASE_DETECTED, +} SwitchState; + +static SwitchData buttonFunctionPair[] = {{GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL}}; + +ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER); + +/********************* Zigbee functions **************************/ +static void onZbButton(SwitchData *button_func_pair) { + if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) { + // Send toggle command to the light + zbSwitch.lightToggle(); + } +} + +/********************* GPIO functions **************************/ +static QueueHandle_t gpio_evt_queue = NULL; + +static void IRAM_ATTR onGpioInterrupt(void *arg) { + xQueueSendFromISR(gpio_evt_queue, (SwitchData *)arg, NULL); +} + +static void enableGpioInterrupt(bool enabled) { + for (int i = 0; i < PAIR_SIZE(buttonFunctionPair); ++i) { + if (enabled) { + enableInterrupt((buttonFunctionPair[i]).pin); + } else { + disableInterrupt((buttonFunctionPair[i]).pin); + } + } +} + +/********************* Arduino functions **************************/ +void setup() { + + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + //Optional: set Zigbee device name and model + zbSwitch.setManufacturerAndModel("Espressif", "ZigbeeSwitch"); + + //Optional to allow multiple light to bind to the switch + zbSwitch.allowMultipleBinding(true); + + //Add endpoint to Zigbee Core + log_d("Adding ZigbeeSwitch endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbSwitch); + + //Open network for 180 seconds after boot + Zigbee.setRebootOpenNetwork(180); + + // Init button switch + for (int i = 0; i < PAIR_SIZE(buttonFunctionPair); i++) { + pinMode(buttonFunctionPair[i].pin, INPUT_PULLUP); + /* create a queue to handle gpio event from isr */ + gpio_evt_queue = xQueueCreate(10, sizeof(SwitchData)); + if (gpio_evt_queue == 0) { + log_e("Queue was not created and must not be used"); + while (1); + } + attachInterruptArg(buttonFunctionPair[i].pin, onGpioInterrupt, (void *)(buttonFunctionPair + i), FALLING); + } + + // When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode + log_d("Calling Zigbee.begin()"); + Zigbee.begin(ZIGBEE_COORDINATOR); + + Serial.println("Waiting for Light to bound to the switch"); + //Wait for switch to bound to a light: + while (!zbSwitch.isBound()) { + Serial.printf("."); + delay(500); + } + + // Optional: read manufacturer and model name from the bound light + std::list boundLights = zbSwitch.getBoundDevices(); + //List all bound lights + for (const auto &device : boundLights) { + Serial.printf("Device on endpoint %d, short address: 0x%x\n", device->endpoint, device->short_addr); + Serial.printf( + "IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", device->ieee_addr[0], device->ieee_addr[1], device->ieee_addr[2], device->ieee_addr[3], + device->ieee_addr[4], device->ieee_addr[5], device->ieee_addr[6], device->ieee_addr[7] + ); + Serial.printf("Light manufacturer: %s", zbSwitch.readManufacturer(device->endpoint, device->short_addr)); + Serial.printf("Light model: %s", zbSwitch.readModel(device->endpoint, device->short_addr)); + } + + Serial.println(); +} + +void loop() { + // Handle button switch in loop() + uint8_t pin = 0; + SwitchData buttonSwitch; + static SwitchState buttonState = SWITCH_IDLE; + bool eventFlag = false; + + /* check if there is any queue received, if yes read out the buttonSwitch */ + if (xQueueReceive(gpio_evt_queue, &buttonSwitch, portMAX_DELAY)) { + pin = buttonSwitch.pin; + enableGpioInterrupt(false); + eventFlag = true; + } + while (eventFlag) { + bool value = digitalRead(pin); + switch (buttonState) { + case SWITCH_IDLE: buttonState = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE; break; + case SWITCH_PRESS_DETECTED: buttonState = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED; break; + case SWITCH_RELEASE_DETECTED: + buttonState = SWITCH_IDLE; + /* callback to button_handler */ + (*onZbButton)(&buttonSwitch); + break; + default: break; + } + if (buttonState == SWITCH_IDLE) { + enableGpioInterrupt(true); + eventFlag = false; + break; + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } + + // print the bound lights every 10 seconds + static uint32_t lastPrint = 0; + if (millis() - lastPrint > 10000) { + lastPrint = millis(); + zbSwitch.printBoundDevices(); + } +} diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json new file mode 100644 index 00000000000..c916121b991 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json @@ -0,0 +1,16 @@ +{ + "fqbn": { + "esp32c6": [ + "espressif:esp32:esp32c6:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" + ], + "esp32h2": [ + "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" + ] + }, + "targets": { + "esp32": false, + "esp32c3": false, + "esp32s2": false, + "esp32s3": false + } +} diff --git a/libraries/Zigbee/examples/Zigbee_Scan_Networks/README.md b/libraries/Zigbee/examples/Zigbee_Scan_Networks/README.md new file mode 100644 index 00000000000..0b2b2f94695 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Scan_Networks/README.md @@ -0,0 +1,71 @@ +# Arduino-ESP32 Zigbee Networks Scan Example + +This example shows how to scan Zigbee Networks. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Example Output + + Setup done + Loop running... + Loop running... + Loop running... + Loop running... + + Scan done + 2 networks found: + Nr | PAN ID | CH | Permit Joining | Router Capacity | End Device Capacity | Extended PAN ID + 1 | 0xe6f0 | 14 | Yes | Yes | Yes | f0:f5:bd:ff:fe:02:3f:24 + 2 | 0xa9bb | 24 | No | Yes | Yes | 60:55:f9:00:00:f7:52:d0 + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with `Zigbee_Thermostat` example) +* A USB cable for power supply and programming +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device (loaded with `Zigbee_Temperature_Sensor` example) + +### Configure the Project + +In this example, the internal temperature sensor task is reading the chip temperature. +Set the Button Switch GPIO by changing the `GPIO_INPUT_IO_TOGGLE_SWITCH` definition. By default, it's the `GPIO_NUM_9` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino b/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino new file mode 100644 index 00000000000..a72ade201ae --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino @@ -0,0 +1,113 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee Network Scanning. + * + * The example demonstrates how to use ESP Zigbee stack to scan for Zigbee networks. + * + * Any Zigbee mode can be selected in Tools->Zigbee mode + * with proper Zigbee partition scheme in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#if !defined(ZIGBEE_MODE_ED) && !defined(ZIGBEE_MODE_ZCZR) +#error "Zigbee device mode is not selected in Tools->Zigbee mode" +#endif + +#include "ZigbeeCore.h" + +#ifdef ZIGBEE_MODE_ZCZR +zigbee_role_t role = ZIGBEE_ROUTER; // or can be ZIGBEE_COORDINATOR, but it wont scan itself +#else +zigbee_role_t role = ZIGBEE_END_DEVICE; +#endif + +void printScannedNetworks(uint16_t networksFound) { + if (networksFound == 0) { + Serial.println("No networks found"); + } else { + zigbee_scan_result_t *scan_result = Zigbee.getScanResult(); + Serial.println("\nScan done"); + Serial.print(networksFound); + Serial.println(" networks found:"); + Serial.println("Nr | PAN ID | CH | Permit Joining | Router Capacity | End Device Capacity | Extended PAN ID"); + for (int i = 0; i < networksFound; ++i) { + // Print all available info for each network found + Serial.printf("%2d", i + 1); + Serial.print(" | "); + Serial.printf("0x%04hx", scan_result[i].short_pan_id); + Serial.print(" | "); + Serial.printf("%2d", scan_result[i].logic_channel); + Serial.print(" | "); + Serial.printf("%-14.14s", scan_result[i].permit_joining ? "Yes" : "No"); + Serial.print(" | "); + Serial.printf("%-15.15s", scan_result[i].router_capacity ? "Yes" : "No"); + Serial.print(" | "); + Serial.printf("%-19.19s", scan_result[i].end_device_capacity ? "Yes" : "No"); + Serial.print(" | "); + Serial.printf( + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", scan_result[i].extended_pan_id[7], scan_result[i].extended_pan_id[6], scan_result[i].extended_pan_id[5], + scan_result[i].extended_pan_id[4], scan_result[i].extended_pan_id[3], scan_result[i].extended_pan_id[2], scan_result[i].extended_pan_id[1], + scan_result[i].extended_pan_id[0] + ); + Serial.println(); + delay(10); + } + Serial.println(""); + // Delete the scan result to free memory for code below. + Zigbee.scanDelete(); + } +} + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + // Initialize Zigbee stack without any EPs just for scanning + Zigbee.begin(role); + + // Waint until Zigbee stack is ready + while (!Zigbee.isStarted()) { + delay(100); + } + + Serial.println("Setup done"); + // Start Zigbee Network Scan with default parameters (all channels, scan time 5) + Zigbee.scanNetworks(); +} + +void loop() { + // check Zigbee Network Scan process + int16_t ZigbeeScanStatus = Zigbee.scanComplete(); + if (ZigbeeScanStatus < 0) { // it is busy scanning or got an error + if (ZigbeeScanStatus == ZB_SCAN_FAILED) { + Serial.println("WiFi Scan has failed. Starting again."); + Zigbee.scanNetworks(); + } + // other option is status ZB_SCAN_RUNNING - just wait. + } else { // Found Zero or more Wireless Networks + printScannedNetworks(ZigbeeScanStatus); + Zigbee.scanNetworks(); // start over... + } + + // Loop can do something else... + delay(500); + Serial.println("Loop running..."); +} diff --git a/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json b/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json new file mode 100644 index 00000000000..3aaf44eb376 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json @@ -0,0 +1,16 @@ +{ + "fqbn": { + "esp32c6": [ + "espressif:esp32:esp32c6:PartitionScheme=zigbee,ZigbeeMode=ed" + ], + "esp32h2": [ + "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" + ] + }, + "targets": { + "esp32": false, + "esp32c3": false, + "esp32s2": false, + "esp32s3": false + } +} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/README.md similarity index 59% rename from libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/README.md rename to libraries/Zigbee/examples/Zigbee_Temperature_Sensor/README.md index f8177082a8a..f3dd9248f87 100644 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Temperature_Sensor/README.md +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/README.md @@ -2,8 +2,6 @@ This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) temperature sensor. -**This example is based on ESP-Zigbee-SDK example esp_zigbee_HA_sample/HA_temperature_sensor.** - # Supported Targets Currently, this example supports the following targets. @@ -14,23 +12,23 @@ Currently, this example supports the following targets. ## Temperature Sensor Functions Note: - * This board means the board (e.g. ESP32-H2) loaded with `Zigbee_Temperature_Sensor` example. - * The remote board means the board (e.g. ESP32-H2) loaded with `Zigbee_Thermostat` example. + * This board means the board (e.g. ESP32-H2 / C6) loaded with `Zigbee_Temperature_Sensor` example. + * The remote board means the board (e.g. ESP32-H2 / C6) loaded with `Zigbee_Thermostat` example. Functions: * After this board first starts up, it would be configured locally to report the temperature on 1 degree change and no periodic reporting to the remote board. - * By clicking the switch button (BOOT) on this board, this board will immediately send a report of the current measured temperature to the remote board. + * By clicking the button (BOOT) on this board, this board will immediately send a report of the current measured temperature to the remote board. ## Hardware Required * One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with `Zigbee_Thermostat` example) * A USB cable for power supply and programming -* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device (loaded with `Zigbee_Temperature_Sensor` example) +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the `Zigbee_Temperature_Sensor` example ### Configure the Project In this example, the internal temperature sensor task is reading the chip temperature. -Set the Button Switch GPIO by changing the `GPIO_INPUT_IO_TOGGLE_SWITCH` definition. By default, it's the `GPIO_NUM_9` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Button GPIO by changing the `BUTTON_PIN` definition. By default, it's the pin `9` (BOOT button on ESP32-C6 and ESP32-H2). #### Using Arduino IDE @@ -40,17 +38,21 @@ To get more information about the Espressif boards see [Espressif Development Ki * Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` * Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. ## Troubleshooting -If the End device flashed with this example is not connecting to the coordinator, erase the flash before flashing it to the board. It is recommended to do this if you did changes to the coordinator. +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. You can do the following: -* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled` -* In the sketch uncomment function `esp_zb_nvram_erase_at_start(true);` located in `esp_zb_task` function. +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: -By default, the coordinator network is open for 180 s after rebooting or flashing new firmware. After that, the network is closed for adding new devices. -You can change it by editing `esp_zb_bdb_open_network(180);` in `esp_zb_app_signal_handler` function. +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. ***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** @@ -70,14 +72,8 @@ Before creating a new issue, be sure to try Troubleshooting and check if the sam ## Resources -The ESP Zigbee SDK provides more examples: -* ESP Zigbee SDK Docs: [Link](https://docs.espressif.com/projects/esp-zigbee-sdk) -* ESP Zigbee SDK Repo: [Link](https://github.com/espressif/esp-zigbee-sdk) - * Official ESP32 Forum: [Link](https://esp32.com) * Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) -* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) -* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) -* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) -* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) * Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino new file mode 100644 index 00000000000..92249e980ab --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino @@ -0,0 +1,107 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature sensor. + * + * The example demonstrates how to use Zigbee library to create a end device temperature sensor. + * The temperature sensor is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#include "ZigbeeCore.h" +#include "ep/ZigbeeTempSensor.h" + +#define BUTTON_PIN 9 //Boot button for C6/H2 +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + // Read temperature sensor value + float tsens_value = temperatureRead(); + log_v("Temperature sensor value: %.2f°C", tsens_value); + // Update temperature value in Temperature sensor EP + zbTempSensor.setTemperature(tsens_value); + delay(1000); + } +} + +/********************* Arduino functions **************************/ +void setup() { + + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + // Init button switch + pinMode(BUTTON_PIN, INPUT); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "ZigbeeTempSensor"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // When all EPs are registered, start Zigbee in End Device mode + Zigbee.begin(); + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + zbTempSensor.setReporting(1, 0, 1); +} + +void loop() { + // Checking button for factory reset + if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(BUTTON_PIN) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.printf("Resetting Zigbee to factory settings, reboot.\n"); + Zigbee.factoryReset(); + } + } + zbTempSensor.reportTemperature(); + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json new file mode 100644 index 00000000000..3aaf44eb376 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json @@ -0,0 +1,16 @@ +{ + "fqbn": { + "esp32c6": [ + "espressif:esp32:esp32c6:PartitionScheme=zigbee,ZigbeeMode=ed" + ], + "esp32h2": [ + "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" + ] + }, + "targets": { + "esp32": false, + "esp32c3": false, + "esp32s2": false, + "esp32s3": false + } +} diff --git a/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/README.md b/libraries/Zigbee/examples/Zigbee_Thermostat/README.md similarity index 64% rename from libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/README.md rename to libraries/Zigbee/examples/Zigbee_Thermostat/README.md index 5c88feda311..e61173f6f4d 100644 --- a/libraries/ESP32/examples/Zigbee/Zigbee_Thermostat/README.md +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/README.md @@ -18,7 +18,7 @@ Note: * The remote board means the board (e.g. ESP32-H2) loaded with `Zigbee_Temperature_Sensor` example. Functions: - * By clicking the switch button (BOOT) on this board, this board will read temperature value, temperature measurement range and temperature tolerance from the remote board. Also, this board will configure the remote board to report the measured temperature value every 10 seconds or every 2 degree changes. + * By clicking the button (BOOT) on this board, this board will read temperature value, temperature measurement range and temperature tolerance from the remote board. Also, this board will configure the remote board to report the measured temperature value every 10 seconds or every 2 degree changes. ## Hardware Required @@ -28,17 +28,17 @@ Functions: ### Configure the Project -Set the Button Switch GPIO by changing the `GPIO_INPUT_IO_TOGGLE_SWITCH` definition. By default, it's the `GPIO_NUM_9` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Button GPIO by changing the `BUTTON_PIN` definition. By default, it's the pin `9` (BOOT button on ESP32-C6 and ESP32-H2). #### Using Arduino IDE To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). * Before Compile/Verify, select the correct board: `Tools -> Board`. -* Select the Coordinator Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator)`. +* Select the Coordinator Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)`. * Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs`. * Select the COM port: `Tools -> Port: xxx where the `xxx` is the detected COM port. -* Optional: Set debug level to info to see logs from Zigbee stack: `Tools -> Core Debug Level: Info`. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. ## Troubleshooting @@ -46,10 +46,13 @@ If the End device flashed with the example `Zigbee_Temperature_Sensor` is not co You can do the following: * In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. -* In the `Zigbee_Temperature_Sensor` example sketch uncomment function `esp_zb_nvram_erase_at_start(true);` located in `esp_zb_task` function. +* In the `Zigbee_Temperature_Sensor` example sketch call `Zigbee.factoryReset();`. -By default, the coordinator network is open for 180 s after rebooting or flashing new firmware. After that, the network is closed for adding new devices. -You can change it by editing `esp_zb_bdb_open_network(180);` in `esp_zb_app_signal_handler` function. +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. ***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** @@ -69,14 +72,8 @@ Before creating a new issue, be sure to try Troubleshooting and check if the sam ## Resources -The ESP Zigbee SDK provides more examples: -* ESP Zigbee SDK Docs: [Link](https://docs.espressif.com/projects/esp-zigbee-sdk) -* ESP Zigbee SDK Repo: [Link](https://github.com/espressif/esp-zigbee-sdk) - * Official ESP32 Forum: [Link](https://esp32.com) * Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) -* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) -* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) -* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) -* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) * Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino new file mode 100644 index 00000000000..8f4ea0b543d --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino @@ -0,0 +1,119 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates simple Zigbee thermostat. + * + * The example demonstrates how to use Zigbee library to get data from temperature + * sensor end device and act as an thermostat. + * The temperature sensor is a Zigbee end device, which is controlled by a Zigbee coordinator (thermostat). + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#include "ZigbeeCore.h" +#include "ep/ZigbeeThermostat.h" + +#define BUTTON_PIN 9 // Boot button for C6/H2 +#define THERMOSTAT_ENDPOINT_NUMBER 5 + +ZigbeeThermostat zbThermostat = ZigbeeThermostat(THERMOSTAT_ENDPOINT_NUMBER); + +// Save temperature sensor data +float sensor_temp; +float sensor_max_temp; +float sensor_min_temp; +float sensor_tolerance; + +/****************** Temperature sensor handling *******************/ +void recieveSensorTemp(float temperature) { + Serial.printf("Temperature sensor value: %.2f°C\n", temperature); + sensor_temp = temperature; +} + +void recieveSensorConfig(float min_temp, float max_temp, float tolerance) { + Serial.printf("Temperature sensor settings: min %.2f°C, max %.2f°C, tolerance %.2f°C\n", min_temp, max_temp, tolerance); + sensor_min_temp = min_temp; + sensor_max_temp = max_temp; + sensor_tolerance = tolerance; +} +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + // Init button switch + pinMode(BUTTON_PIN, INPUT); + + // Set callback functions for temperature and configuration receive + zbThermostat.onTempRecieve(recieveSensorTemp); + zbThermostat.onConfigRecieve(recieveSensorConfig); + + //Optional: set Zigbee device name and model + zbThermostat.setManufacturerAndModel("Espressif", "ZigbeeThermostat"); + + //Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbThermostat); + + //Open network for 180 seconds after boot + Zigbee.setRebootOpenNetwork(180); + + // When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode + Zigbee.begin(ZIGBEE_COORDINATOR); + + Serial.println("Waiting for Temperature sensor to bound to the switch"); + + //Wait for switch to bound to a light: + while (!zbThermostat.isBound()) { + Serial.printf("."); + delay(500); + } + + // Get temperature sensor configuration + zbThermostat.getSensorSettings(); + Serial.println(); +} + +void loop() { + // Handle button switch in loop() + if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + + // Key debounce handling + while (digitalRead(BUTTON_PIN) == LOW) { + delay(50); + } + + // Set reporting interval for temperature sensor + zbThermostat.setTemperatureReporting(0, 10, 2); + } + + // Print temperature sensor data each 10 seconds + static uint32_t last_print = 0; + if (millis() - last_print > 10000) { + last_print = millis(); + int temp_percent = (int)((sensor_temp - sensor_min_temp) / (sensor_max_temp - sensor_min_temp) * 100); + Serial.printf("Loop temperature info: %.2f°C (%d %%)\n", sensor_temp, temp_percent); + } +} diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json b/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json new file mode 100644 index 00000000000..c916121b991 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json @@ -0,0 +1,16 @@ +{ + "fqbn": { + "esp32c6": [ + "espressif:esp32:esp32c6:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" + ], + "esp32h2": [ + "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" + ] + }, + "targets": { + "esp32": false, + "esp32c3": false, + "esp32s2": false, + "esp32s3": false + } +} diff --git a/libraries/Zigbee/keywords.txt b/libraries/Zigbee/keywords.txt new file mode 100644 index 00000000000..53ce5fffe2a --- /dev/null +++ b/libraries/Zigbee/keywords.txt @@ -0,0 +1,105 @@ +####################################### +# Syntax Coloring Map For Zigbee +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +# Base Classes +ZigbeeCore KEYWORD1 +Zigbee KEYWORD1 +ZigbeeEP KEYWORD1 + +# Endpoint Classes +ZigbeeLight KEYWORD1 +ZigbeeSwitch KEYWORD1 +ZigbeeColorDimmableLight KEYWORD1 +ZigbeeColorDimmerSwitch KEYWORD1 +ZigbeeTempSensor KEYWORD1 +ZigbeeThermostat KEYWORD1 + +# Other +zigbee_role_t KEYWORD1 +zbstring_t KEYWORD1 +zb_device_params_t KEYWORD1 +zigbee_scan_result_t KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +# ZigbeeCore +isStarted KEYWORD2 +addEndpoint KEYWORD2 +setRadioConfig KEYWORD2 +setHostConfig KEYWORD2 +getRadioConfig KEYWORD2 +getHostConfig KEYWORD2 +setPrimaryChannelMask KEYWORD2 +setRebootOpenNetwork KEYWORD2 +scanNetworks KEYWORD2 +scanComplete KEYWORD2 +getScanResult KEYWORD2 +scanDelete KEYWORD2 +factoryReset KEYWORD2 + +# Common ZigbeeEP +setVersion KEYWORD2 +setManufacturerAndModel KEYWORD2 +is_bound KEYWORD2 +printBoundDevices KEYWORD2 +allowMultipleBinding KEYWORD2 + +# ZigbeeLight + ZigbeeColorDimmableLight +setOnOff KEYWORD2 +sceneControl KEYWORD2 +setOnOffTime KEYWORD2 +setOffWaitTime KEYWORD2 +setLevel KEYWORD2 +setColor KEYWORD2 +setColorSaturation KEYWORD2 +setColorHue KEYWORD2 + +# ZigbeeSwitch + ZigbeeColorDimmerSwitch +lightToggle KEYWORD2 +lightOn KEYWORD2 +lightOff KEYWORD2 +lightOffWithEffect KEYWORD2 +lightOnWithTimedOff KEYWORD2 +lightOnWithSceneRecall KEYWORD2 +setLightLevel KEYWORD2 +setLightColor KEYWORD2 +setLightColorSaturation KEYWORD2 +setLightColorHue KEYWORD2 + +# ZigbeeTempSensor +setTemperature KEYWORD2 +setMinMaxValue KEYWORD2 +setTolerance KEYWORD2 +setReporting KEYWORD2 +reportTemperature KEYWORD2 + +# ZigbeeThermostat +temperatureRead KEYWORD2 +temperatureMin KEYWORD2 +temperatureMax KEYWORD2 +temperatureTolerance KEYWORD2 +getTemperature KEYWORD2 +setTemperatureReporting KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +ZIGBEE_COORDINATOR LITERAL1 +ZIGBEE_ROUTER LITERAL1 +ZIGBEE_END_DEVICE LITERAL1 +ZIGBEE_DEFAULT_ED_CONFIG LITERAL1 +ZIGBEE_DEFAULT_ROUTER_CONFIG LITERAL1 +ZIGBEE_DEFAULT_COORDINATOR_CONFIG LITERAL1 +ZIGBEE_DEFAULT_RADIO_CONFIG LITERAL1 +ZIGBEE_DEFAULT_HOST_CONFIG LITERAL1 +ZB_ARRAY_LENTH LITERAL1 +XYZ_TO_RGB LITERAL1 +RGB_TO_XYZ LITERAL1 diff --git a/libraries/Zigbee/library.properties b/libraries/Zigbee/library.properties new file mode 100644 index 00000000000..4d66f470378 --- /dev/null +++ b/libraries/Zigbee/library.properties @@ -0,0 +1,9 @@ +name=Zigbee +version=3.0.5 +author=P-R-O-C-H-Y +maintainer=Jan Procházka +sentence=Enables zigbee connection with the ESP32 +paragraph=With this library you can create zigbee end devices, routers, coordinators and connect them to the zigbee network. +category=Communication +url= +architectures=esp32 diff --git a/libraries/Zigbee/src/ZigbeeCore.cpp b/libraries/Zigbee/src/ZigbeeCore.cpp new file mode 100644 index 00000000000..9edbe737cfe --- /dev/null +++ b/libraries/Zigbee/src/ZigbeeCore.cpp @@ -0,0 +1,396 @@ +/* Zigbee Core Functions */ + +#include "ZigbeeCore.h" +#if SOC_IEEE802154_SUPPORTED + +#include "ZigbeeHandlers.cpp" +#include "Arduino.h" + +ZigbeeCore::ZigbeeCore() { + _radio_config.radio_mode = ZB_RADIO_MODE_NATIVE; // Use the native 15.4 radio + _host_config.host_connection_mode = ZB_HOST_CONNECTION_MODE_NONE; // Disable host connection + _zb_ep_list = esp_zb_ep_list_create(); + _primary_channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK; + _open_network = 0; + _scan_status = ZB_SCAN_FAILED; + _started = false; +} +ZigbeeCore::~ZigbeeCore() {} + +//forward declaration +static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message); + +bool ZigbeeCore::begin(esp_zb_cfg_t *role_cfg, bool erase_nvs) { + if (!zigbeeInit(role_cfg, erase_nvs)) { + return false; + } + _role = (zigbee_role_t)role_cfg->esp_zb_role; + return true; +} + +bool ZigbeeCore::begin(zigbee_role_t role, bool erase_nvs) { + bool status = true; + switch (role) { + case ZIGBEE_COORDINATOR: + { + _role = ZIGBEE_COORDINATOR; + esp_zb_cfg_t zb_nwk_cfg = ZIGBEE_DEFAULT_COORDINATOR_CONFIG(); + status = zigbeeInit(&zb_nwk_cfg, erase_nvs); + break; + } + case ZIGBEE_ROUTER: + { + _role = ZIGBEE_ROUTER; + esp_zb_cfg_t zb_nwk_cfg = ZIGBEE_DEFAULT_ROUTER_CONFIG(); + status = zigbeeInit(&zb_nwk_cfg, erase_nvs); + break; + } + case ZIGBEE_END_DEVICE: + { + _role = ZIGBEE_END_DEVICE; + esp_zb_cfg_t zb_nwk_cfg = ZIGBEE_DEFAULT_ED_CONFIG(); + status = zigbeeInit(&zb_nwk_cfg, erase_nvs); + break; + } + default: log_e("Invalid Zigbee Role"); return false; + } + return status; +} + +void ZigbeeCore::addEndpoint(ZigbeeEP *ep) { + ep_objects.push_back(ep); + + log_d("Endpoint: %d, Device ID: 0x%04x", ep->_endpoint, ep->_device_id); + //Register clusters and ep_list to the ZigbeeCore class's ep_list + if (ep->_ep_config.endpoint == 0 || ep->_cluster_list == nullptr) { + log_e("Endpoint config or Cluster list is not initialized, EP not added to ZigbeeCore's EP list"); + return; + } + + esp_zb_ep_list_add_ep(_zb_ep_list, ep->_cluster_list, ep->_ep_config); +} + +static void esp_zb_task(void *pvParameters) { + /* initialize Zigbee stack */ + ESP_ERROR_CHECK(esp_zb_start(false)); + esp_zb_stack_main_loop(); +} + +// Zigbee core init function +bool ZigbeeCore::zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs) { + // Zigbee platform configuration + esp_zb_platform_config_t platform_config = { + .radio_config = _radio_config, + .host_config = _host_config, + }; + + esp_err_t err = esp_zb_platform_config(&platform_config); + if (err != ESP_OK) { + log_e("Failed to configure Zigbee platform"); + return false; + } + + // Initialize Zigbee stack + log_d("Initialize Zigbee stack"); + esp_zb_init(zb_cfg); + + // Register all Zigbee EPs in list + if (ep_objects.empty()) { + log_w("No Zigbee EPs to register"); + } else { + log_d("Register all Zigbee EPs in list"); + err = esp_zb_device_register(_zb_ep_list); + if (err != ESP_OK) { + log_e("Failed to register Zigbee EPs"); + return false; + } + + //print the list of Zigbee EPs from ep_objects + log_i("List of registered Zigbee EPs:"); + for (std::list::iterator it = ep_objects.begin(); it != ep_objects.end(); ++it) { + log_i("Device type: %s, Endpoint: %d, Device ID: 0x%04x", getDeviceTypeString((*it)->_device_id), (*it)->_endpoint, (*it)->_device_id); + } + } + // Register Zigbee action handler + esp_zb_core_action_handler_register(zb_action_handler); + err = esp_zb_set_primary_network_channel_set(_primary_channel_mask); + if (err != ESP_OK) { + log_e("Failed to set primary network channel mask"); + return false; + } + + //Erase NVRAM before creating connection to new Coordinator + if (erase_nvs) { + esp_zb_nvram_erase_at_start(true); + } + + // Create Zigbee task and start Zigbee stack + xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL); + + return true; +} + +void ZigbeeCore::setRadioConfig(esp_zb_radio_config_t config) { + _radio_config = config; +} + +esp_zb_radio_config_t ZigbeeCore::getRadioConfig() { + return _radio_config; +} + +void ZigbeeCore::setHostConfig(esp_zb_host_config_t config) { + _host_config = config; +} + +esp_zb_host_config_t ZigbeeCore::getHostConfig() { + return _host_config; +} + +void ZigbeeCore::setPrimaryChannelMask(uint32_t mask) { + _primary_channel_mask = mask; +} + +void ZigbeeCore::setRebootOpenNetwork(uint8_t time) { + _open_network = time; +} + +void ZigbeeCore::openNetwork(uint8_t time) { + if (_started) { + log_v("Opening network for joining for %d seconds", time); + esp_zb_bdb_open_network(time); + } +} + +static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) { + ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); +} + +void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { + //common variables + 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 = (esp_zb_app_signal_type_t)*p_sg_p; + //coordinator variables + esp_zb_zdo_signal_device_annce_params_t *dev_annce_params = NULL; + + //main switch + switch (sig_type) { + case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: // Common + log_i("Zigbee stack initialized"); + esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION); + break; + case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: // Common + case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: // Common + if (err_status == ESP_OK) { + log_i("Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non"); + if (esp_zb_bdb_is_factory_new()) { + // Role specific code + if ((zigbee_role_t)Zigbee.getRole() == ZIGBEE_COORDINATOR) { + log_i("Start network formation"); + esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); + } else { + log_i("Start network steering"); + esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); + } + //----------------- + + } else { + log_i("Device rebooted"); + Zigbee._started = true; + if ((zigbee_role_t)Zigbee.getRole() == ZIGBEE_COORDINATOR && Zigbee._open_network > 0) { + log_i("Opening network for joining for %d seconds", Zigbee._open_network); + esp_zb_bdb_open_network(Zigbee._open_network); + } + } + } else { + /* commissioning failed */ + log_e("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); + } + break; + case ESP_ZB_BDB_SIGNAL_FORMATION: // Coordinator + if ((zigbee_role_t)Zigbee.getRole() == ZIGBEE_COORDINATOR) { + if (err_status == ESP_OK) { + esp_zb_ieee_addr_t extended_pan_id; + esp_zb_get_extended_pan_id(extended_pan_id); + log_i( + "Formed network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", + 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(), esp_zb_get_short_address() + ); + esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); + } else { + log_i("Restart network formation (status: %s)", 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_FORMATION, 1000); + } + } + break; + case ESP_ZB_BDB_SIGNAL_STEERING: // Router and End Device + Zigbee._started = true; + if ((zigbee_role_t)Zigbee.getRole() == ZIGBEE_COORDINATOR) { + if (err_status == ESP_OK) { + log_i("Network steering started"); + } + } else { + if (err_status == ESP_OK) { + esp_zb_ieee_addr_t extended_pan_id; + esp_zb_get_extended_pan_id(extended_pan_id); + log_i( + "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", + 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(), esp_zb_get_short_address() + ); + } else { + log_i("Network steering was not successful (status: %s)", 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); + } + } + break; + case ESP_ZB_ZDO_SIGNAL_DEVICE_ANNCE: // Coordinator + if ((zigbee_role_t)Zigbee.getRole() == ZIGBEE_COORDINATOR) { + dev_annce_params = (esp_zb_zdo_signal_device_annce_params_t *)esp_zb_app_signal_get_params(p_sg_p); + log_i("New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr); + esp_zb_zdo_match_desc_req_param_t cmd_req; + cmd_req.dst_nwk_addr = dev_annce_params->device_short_addr; + cmd_req.addr_of_interest = dev_annce_params->device_short_addr; + log_v("Device capabilities: 0x%02x", dev_annce_params->capability); + /* + capability: + Bit 0 – Alternate PAN Coordinator + Bit 1 – Device type: 1- ZigBee Router; 0 – End Device + Bit 2 – Power Source: 1 Main powered + Bit 3 – Receiver on when Idle + Bit 4 – Reserved + Bit 5 – Reserved + Bit 6 – Security capability + Bit 7 – Reserved + */ + + // for each endpoint in the list call the findEndpoint function if not bounded or allowed to bind multiple devices + for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { + if (!(*it)->isBound() || (*it)->epAllowMultipleBinding()) { + (*it)->findEndpoint(&cmd_req); + } + } + } + break; + case ESP_ZB_NWK_SIGNAL_PERMIT_JOIN_STATUS: // Coordinator + if ((zigbee_role_t)Zigbee.getRole() == ZIGBEE_COORDINATOR) { + if (err_status == ESP_OK) { + if (*(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)) { + log_i("Network(0x%04hx) is open for %d seconds", esp_zb_get_pan_id(), *(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)); + } else { + log_i("Network(0x%04hx) closed, devices joining not allowed.", esp_zb_get_pan_id()); + } + } + } + break; + default: log_v("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 ZigbeeCore::factoryReset() { + log_v("Factory resetting Zigbee stack, device will reboot"); + esp_zb_factory_reset(); +} + +void ZigbeeCore::scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t count, esp_zb_network_descriptor_t *nwk_descriptor) { + log_v("Zigbee network scan complete"); + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + log_v("Found %d networks", count); + //print Zigbee networks + for (int i = 0; i < count; i++) { + log_v( + "Network %d: PAN ID: 0x%04hx, Permit Joining: %s, Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, Channel: %d, Router Capacity: %s, End " + "Device Capacity: %s", + i, nwk_descriptor[i].short_pan_id, nwk_descriptor[i].permit_joining ? "Yes" : "No", nwk_descriptor[i].extended_pan_id[7], + nwk_descriptor[i].extended_pan_id[6], nwk_descriptor[i].extended_pan_id[5], nwk_descriptor[i].extended_pan_id[4], nwk_descriptor[i].extended_pan_id[3], + nwk_descriptor[i].extended_pan_id[2], nwk_descriptor[i].extended_pan_id[1], nwk_descriptor[i].extended_pan_id[0], nwk_descriptor[i].logic_channel, + nwk_descriptor[i].router_capacity ? "Yes" : "No", nwk_descriptor[i].end_device_capacity ? "Yes" : "No" + ); + } + //save scan result and update scan status + //copy network descriptor to _scan_result to keep the data after the callback + Zigbee._scan_result = (esp_zb_network_descriptor_t *)malloc(count * sizeof(esp_zb_network_descriptor_t)); + memcpy(Zigbee._scan_result, nwk_descriptor, count * sizeof(esp_zb_network_descriptor_t)); + Zigbee._scan_status = count; + } else { + log_e("Failed to scan Zigbee network (status: 0x%x)", zdo_status); + Zigbee._scan_status = ZB_SCAN_FAILED; + Zigbee._scan_result = nullptr; + } +} + +void ZigbeeCore::scanNetworks(u_int32_t channel_mask, u_int8_t scan_duration) { + if (!_started) { + log_e("Zigbee stack is not started, cannot scan networks"); + return; + } + log_v("Scanning Zigbee networks"); + esp_zb_zdo_active_scan_request(channel_mask, scan_duration, scanCompleteCallback); + _scan_status = ZB_SCAN_RUNNING; +} + +int16_t ZigbeeCore::scanComplete() { + return _scan_status; +} + +zigbee_scan_result_t *ZigbeeCore::getScanResult() { + return _scan_result; +} + +void ZigbeeCore::scanDelete() { + if (_scan_result != nullptr) { + free(_scan_result); + _scan_result = nullptr; + } + _scan_status = ZB_SCAN_FAILED; +} + +// Function to convert enum value to string +const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId) { + switch (deviceId) { + case ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID: return "General On/Off switch"; + case ESP_ZB_HA_LEVEL_CONTROL_SWITCH_DEVICE_ID: return "Level Control Switch"; + case ESP_ZB_HA_ON_OFF_OUTPUT_DEVICE_ID: return "General On/Off output"; + case ESP_ZB_HA_LEVEL_CONTROLLABLE_OUTPUT_DEVICE_ID: return "Level Controllable Output"; + case ESP_ZB_HA_SCENE_SELECTOR_DEVICE_ID: return "Scene Selector"; + case ESP_ZB_HA_CONFIGURATION_TOOL_DEVICE_ID: return "Configuration Tool"; + case ESP_ZB_HA_REMOTE_CONTROL_DEVICE_ID: return "Remote Control"; + case ESP_ZB_HA_COMBINED_INTERFACE_DEVICE_ID: return "Combined Interface"; + case ESP_ZB_HA_RANGE_EXTENDER_DEVICE_ID: return "Range Extender"; + case ESP_ZB_HA_MAINS_POWER_OUTLET_DEVICE_ID: return "Mains Power Outlet"; + case ESP_ZB_HA_DOOR_LOCK_DEVICE_ID: return "Door lock client"; + case ESP_ZB_HA_DOOR_LOCK_CONTROLLER_DEVICE_ID: return "Door lock controller"; + case ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID: return "Simple Sensor device"; + case ESP_ZB_HA_CONSUMPTION_AWARENESS_DEVICE_ID: return "Consumption Awareness Device"; + case ESP_ZB_HA_HOME_GATEWAY_DEVICE_ID: return "Home Gateway"; + case ESP_ZB_HA_SMART_PLUG_DEVICE_ID: return "Smart plug"; + case ESP_ZB_HA_WHITE_GOODS_DEVICE_ID: return "White Goods"; + case ESP_ZB_HA_METER_INTERFACE_DEVICE_ID: return "Meter Interface"; + case ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID: return "On/Off Light Device"; + case ESP_ZB_HA_DIMMABLE_LIGHT_DEVICE_ID: return "Dimmable Light Device"; + case ESP_ZB_HA_COLOR_DIMMABLE_LIGHT_DEVICE_ID: return "Color Dimmable Light Device"; + case ESP_ZB_HA_DIMMER_SWITCH_DEVICE_ID: return "Dimmer Switch Device"; + case ESP_ZB_HA_COLOR_DIMMER_SWITCH_DEVICE_ID: return "Color Dimmer Switch Device"; + case ESP_ZB_HA_LIGHT_SENSOR_DEVICE_ID: return "Light Sensor"; + case ESP_ZB_HA_SHADE_DEVICE_ID: return "Shade"; + case ESP_ZB_HA_SHADE_CONTROLLER_DEVICE_ID: return "Shade controller"; + case ESP_ZB_HA_WINDOW_COVERING_DEVICE_ID: return "Window Covering client"; + case ESP_ZB_HA_WINDOW_COVERING_CONTROLLER_DEVICE_ID: return "Window Covering controller"; + case ESP_ZB_HA_HEATING_COOLING_UNIT_DEVICE_ID: return "Heating/Cooling Unit device"; + case ESP_ZB_HA_THERMOSTAT_DEVICE_ID: return "Thermostat Device"; + case ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID: return "Temperature Sensor"; + case ESP_ZB_HA_IAS_CONTROL_INDICATING_EQUIPMENT_ID: return "IAS Control and Indicating Equipment"; + case ESP_ZB_HA_IAS_ANCILLARY_CONTROL_EQUIPMENT_ID: return "IAS Ancillary Control Equipment"; + case ESP_ZB_HA_IAS_ZONE_ID: return "IAS Zone"; + case ESP_ZB_HA_IAS_WARNING_DEVICE_ID: return "IAS Warning Device"; + case ESP_ZB_HA_TEST_DEVICE_ID: return "Custom HA device for test"; + case ESP_ZB_HA_CUSTOM_TUNNEL_DEVICE_ID: return "Custom Tunnel device"; + case ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID: return "Custom Attributes Device"; + default: return "Unknown device type"; + } +} + +ZigbeeCore Zigbee = ZigbeeCore(); + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ZigbeeCore.h b/libraries/Zigbee/src/ZigbeeCore.h new file mode 100644 index 00000000000..1044a9c737c --- /dev/null +++ b/libraries/Zigbee/src/ZigbeeCore.h @@ -0,0 +1,125 @@ +/* Zigbee core class */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_IEEE802154_SUPPORTED + +#include "esp_zigbee_core.h" +#include "zdo/esp_zigbee_zdo_common.h" +#include +#include +#include "ZigbeeEP.h" +class ZigbeeEP; + +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void *); + +typedef esp_zb_network_descriptor_t zigbee_scan_result_t; + +// enum of Zigbee Roles +typedef enum { + ZIGBEE_COORDINATOR = 0, + ZIGBEE_ROUTER = 1, + ZIGBEE_END_DEVICE = 2 +} zigbee_role_t; + +#define ZB_SCAN_RUNNING (-1) +#define ZB_SCAN_FAILED (-2) + +#define ZIGBEE_DEFAULT_ED_CONFIG() \ + { \ + .esp_zb_role = ESP_ZB_DEVICE_TYPE_ED, .install_code_policy = false, \ + .nwk_cfg = { \ + .zed_cfg = \ + { \ + .ed_timeout = ESP_ZB_ED_AGING_TIMEOUT_64MIN, \ + .keep_alive = 3000, \ + }, \ + }, \ + } + +#define ZIGBEE_DEFAULT_ROUTER_CONFIG() \ + { \ + .esp_zb_role = ESP_ZB_DEVICE_TYPE_ROUTER, .install_code_policy = false, .nwk_cfg = { \ + .zczr_cfg = \ + { \ + .max_children = 10, \ + }, \ + } \ + } + +#define ZIGBEE_DEFAULT_COORDINATOR_CONFIG() \ + { \ + .esp_zb_role = ESP_ZB_DEVICE_TYPE_COORDINATOR, .install_code_policy = false, .nwk_cfg = { \ + .zczr_cfg = \ + { \ + .max_children = 10, \ + }, \ + } \ + } + +class ZigbeeCore { +private: + esp_zb_radio_config_t _radio_config; + esp_zb_host_config_t _host_config; + uint32_t _primary_channel_mask; + int16_t _scan_status; + + esp_zb_ep_list_t *_zb_ep_list; + zigbee_role_t _role; + bool _started; + + uint8_t _open_network; + zigbee_scan_result_t *_scan_result; + + bool zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs); + static void scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t count, esp_zb_network_descriptor_t *nwk_descriptor); + const char *getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId); + +public: + ZigbeeCore(); + ~ZigbeeCore(); + + std::list ep_objects; + + bool begin(zigbee_role_t role = ZIGBEE_END_DEVICE, bool erase_nvs = false); + bool begin(esp_zb_cfg_t *role_cfg, bool erase_nvs = false); + // bool end(); + + bool isStarted() { + return _started; + } + zigbee_role_t getRole() { + return _role; + } + + void addEndpoint(ZigbeeEP *ep); + //void removeEndpoint(ZigbeeEP *ep); + + void setRadioConfig(esp_zb_radio_config_t config); + esp_zb_radio_config_t getRadioConfig(); + + void setHostConfig(esp_zb_host_config_t config); + esp_zb_host_config_t getHostConfig(); + + void setPrimaryChannelMask(uint32_t mask); + void setRebootOpenNetwork(uint8_t time); + void openNetwork(uint8_t time); + + //scan_duration Time spent scanning each channel, in units of ((1 << scan_duration) + 1) * a beacon time. (15.36 microseconds) + void scanNetworks(uint32_t channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK, uint8_t scan_duration = 5); + // Zigbee scan complete status check, -2: failed or not started, -1: running, 0: no networks found, >0: number of networks found + int16_t scanComplete(); + zigbee_scan_result_t *getScanResult(); + void scanDelete(); + + void factoryReset(); + + // Friend function declaration to allow access to private members + friend void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct); +}; + +extern ZigbeeCore Zigbee; + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ZigbeeEP.cpp b/libraries/Zigbee/src/ZigbeeEP.cpp new file mode 100644 index 00000000000..af237739327 --- /dev/null +++ b/libraries/Zigbee/src/ZigbeeEP.cpp @@ -0,0 +1,162 @@ +/* Common Class for Zigbee End Point */ + +#include "ZigbeeEP.h" + +#if SOC_IEEE802154_SUPPORTED + +#include "esp_zigbee_cluster.h" + +uint8_t ZigbeeEP::_endpoint = 0; +bool ZigbeeEP::_is_bound = false; +bool ZigbeeEP::_allow_multiple_binding = false; + +/* Zigbee End Device Class */ +ZigbeeEP::ZigbeeEP(uint8_t endpoint) { + _endpoint = endpoint; + _ep_config.endpoint = 0; + _cluster_list = nullptr; +#if !CONFIG_DISABLE_HAL_LOCKS + if (!lock) { + lock = xSemaphoreCreateBinary(); + if (lock == NULL) { + log_e("Semaphore creation failed"); + } + } +#endif +} + +ZigbeeEP::~ZigbeeEP() {} + +void ZigbeeEP::setVersion(uint8_t version) { + _ep_config.app_device_version = version; +} + +void ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) { + // Convert manufacturer to ZCL string + size_t length = strlen(name); + if (length > 32) { + log_e("Manufacturer name is too long"); + return; + } + // Allocate a new array of size length + 2 (1 for the length, 1 for null terminator) + char *zb_name = new char[length + 2]; + // Store the length as the first element + zb_name[0] = static_cast(length); // Cast size_t to char + // Use memcpy to copy the characters to the result array + memcpy(zb_name + 1, name, length); + // Null-terminate the array + zb_name[length + 1] = '\0'; + + // Convert model to ZCL string + length = strlen(model); + if (length > 32) { + log_e("Model name is too long"); + delete[] zb_name; + return; + } + char *zb_model = new char[length + 2]; + zb_model[0] = static_cast(length); + memcpy(zb_model + 1, model, length); + zb_model[length + 1] = '\0'; + + // Get the basic cluster and update the manufacturer and model attributes + esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)zb_name); + esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)zb_model); +} + +char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) { + /* Read peer Manufacture Name & Model Identifier */ + esp_zb_zcl_read_attr_cmd_t read_req; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.zcl_basic_cmd.dst_endpoint = endpoint; + read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC; + + uint16_t attributes[] = { + ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, + }; + read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_field = attributes; + + // clear read manufacturer + _read_manufacturer = nullptr; + + esp_zb_zcl_read_attr_cmd_req(&read_req); + + //Wait for response or timeout + if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) { + log_e("Error while reading manufacturer"); + } + return _read_manufacturer; +} + +char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr) { + /* Read peer Manufacture Name & Model Identifier */ + esp_zb_zcl_read_attr_cmd_t read_req; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.zcl_basic_cmd.dst_endpoint = endpoint; + read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC; + + uint16_t attributes[] = { + ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, + }; + read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_field = attributes; + + // clear read model + _read_model = nullptr; + + esp_zb_zcl_read_attr_cmd_req(&read_req); + + //Wait for response or timeout + //Semaphore take + if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) { + log_e("Error while reading model"); + } + return _read_model; +} + +void ZigbeeEP::printBoundDevices() { + log_i("Bound devices:"); + for ([[maybe_unused]] + const auto &device : _bound_devices) { + log_i("Device on endpoint %d, short address: 0x%x", device->endpoint, device->short_addr); + print_ieee_addr(device->ieee_addr); + } +} + +void ZigbeeEP::zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute) { + /* Basic cluster attributes */ + if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) { + zbstring_t *zbstr = (zbstring_t *)attribute->data.value; + char *string = (char *)malloc(zbstr->len + 1); + memcpy(string, zbstr->data, zbstr->len); + string[zbstr->len] = '\0'; + log_i("Peer Manufacturer is \"%s\"", string); + _read_manufacturer = string; + xSemaphoreGive(lock); + } + if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) { + zbstring_t *zbstr = (zbstring_t *)attribute->data.value; + char *string = (char *)malloc(zbstr->len + 1); + memcpy(string, zbstr->data, zbstr->len); + string[zbstr->len] = '\0'; + log_i("Peer Model is \"%s\"", string); + _read_model = string; + xSemaphoreGive(lock); + } +} + +void ZigbeeEP::zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message) { + if (message->attribute.id == ESP_ZB_ZCL_CMD_IDENTIFY_IDENTIFY_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) { + _on_identify(*(uint16_t *)message->attribute.data.value); + } else { + log_w("Other identify commands are not implemented yet."); + } +} + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ZigbeeEP.h b/libraries/Zigbee/src/ZigbeeEP.h new file mode 100644 index 00000000000..e7deefdb32e --- /dev/null +++ b/libraries/Zigbee/src/ZigbeeEP.h @@ -0,0 +1,124 @@ +/* Common Class for Zigbee End point */ + +#pragma once + +#include "ZigbeeCore.h" +#if SOC_IEEE802154_SUPPORTED + +#include + +/* Useful defines */ +#define ZB_ARRAY_LENTH(arr) (sizeof(arr) / sizeof(arr[0])) +#define print_ieee_addr(addr) \ + log_i("IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]) +#define XYZ_TO_RGB(X, Y, Z, r, g, b) \ + { \ + r = (float)(3.240479 * (X) - 1.537150 * (Y) - 0.498535 * (Z)); \ + g = (float)(-0.969256 * (X) + 1.875992 * (Y) + 0.041556 * (Z)); \ + b = (float)(0.055648 * (X) - 0.204043 * (Y) + 1.057311 * (Z)); \ + if (r > 1) { \ + r = 1; \ + } \ + if (g > 1) { \ + g = 1; \ + } \ + if (b > 1) { \ + b = 1; \ + } \ + } + +#define RGB_TO_XYZ(r, g, b, X, Y, Z) \ + { \ + X = (float)(0.412453 * (r) + 0.357580 * (g) + 0.180423 * (b)); \ + Y = (float)(0.212671 * (r) + 0.715160 * (g) + 0.072169 * (b)); \ + Z = (float)(0.019334 * (r) + 0.119193 * (g) + 0.950227 * (b)); \ + } + +typedef struct zbstring_s { + uint8_t len; + char data[]; +} ESP_ZB_PACKED_STRUCT zbstring_t; + +typedef struct zb_device_params_s { + esp_zb_ieee_addr_t ieee_addr; + uint8_t endpoint; + uint16_t short_addr; +} zb_device_params_t; + +typedef enum { + SINGLE_COLOR = 0, + RGB = 1 +} zb_identify_led_type_t; + +/* Zigbee End Device Class */ +class ZigbeeEP { +public: + ZigbeeEP(uint8_t endpoint = 10); + ~ZigbeeEP(); + + // Set ep config and cluster list + void setEpConfig(esp_zb_endpoint_config_t ep_config, esp_zb_cluster_list_t *cluster_list) { + _ep_config = ep_config; + _cluster_list = cluster_list; + } + + void setVersion(uint8_t version); + uint8_t getEndpoint() { + return _endpoint; + } + + void printBoundDevices(); + std::list getBoundDevices() const { + return _bound_devices; + } + + static bool isBound() { + return _is_bound; + } + static void allowMultipleBinding(bool bind) { + _allow_multiple_binding = bind; + } + + // Manufacturer name and model implemented + void setManufacturerAndModel(const char *name, const char *model); + + // Methods to read manufacturer and model name from selected endpoint and short address + char *readManufacturer(uint8_t endpoint, uint16_t short_addr); + char *readModel(uint8_t endpoint, uint16_t short_addr); + + bool epAllowMultipleBinding() { + return _allow_multiple_binding; + } + + // findEndpoind may be implemented by EPs to find and bind devices + virtual void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {}; + + //list of all handlers function calls, to be override by EPs implementation + virtual void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {}; + virtual void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) {}; + virtual void zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute); //already implemented + virtual void zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message); + + void onIdentify(void (*callback)(uint16_t)) { + _on_identify = callback; + } + +private: + static bool _allow_multiple_binding; + char *_read_manufacturer; + char *_read_model; + void (*_on_identify)(uint16_t time); + +protected: + static uint8_t _endpoint; + esp_zb_ha_standard_devices_t _device_id; + esp_zb_endpoint_config_t _ep_config; + esp_zb_cluster_list_t *_cluster_list; + static bool _is_bound; + std::list _bound_devices; + SemaphoreHandle_t lock; + + friend class ZigbeeCore; +}; + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ZigbeeHandlers.cpp b/libraries/Zigbee/src/ZigbeeHandlers.cpp new file mode 100644 index 00000000000..9522b0ba1a8 --- /dev/null +++ b/libraries/Zigbee/src/ZigbeeHandlers.cpp @@ -0,0 +1,141 @@ +/* Zigbee Common Functions */ +#include "ZigbeeCore.h" +#include "Arduino.h" + +#if SOC_IEEE802154_SUPPORTED + +// forward declaration of all implemented handlers +static esp_err_t zb_attribute_set_handler(const esp_zb_zcl_set_attr_value_message_t *message); +static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_message_t *message); +static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message); +static esp_err_t zb_configure_report_resp_handler(const esp_zb_zcl_cmd_config_report_resp_message_t *message); +static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_message_t *message); + +// Zigbee action handlers +[[maybe_unused]] +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_SET_ATTR_VALUE_CB_ID: ret = zb_attribute_set_handler((esp_zb_zcl_set_attr_value_message_t *)message); break; + case ESP_ZB_CORE_REPORT_ATTR_CB_ID: ret = zb_attribute_reporting_handler((esp_zb_zcl_report_attr_message_t *)message); break; + case ESP_ZB_CORE_CMD_READ_ATTR_RESP_CB_ID: ret = zb_cmd_read_attr_resp_handler((esp_zb_zcl_cmd_read_attr_resp_message_t *)message); break; + case ESP_ZB_CORE_CMD_REPORT_CONFIG_RESP_CB_ID: ret = zb_configure_report_resp_handler((esp_zb_zcl_cmd_config_report_resp_message_t *)message); break; + case ESP_ZB_CORE_CMD_DEFAULT_RESP_CB_ID: ret = zb_cmd_default_resp_handler((esp_zb_zcl_cmd_default_resp_message_t *)message); break; + default: log_w("Receive unhandled Zigbee action(0x%x) callback", callback_id); break; + } + return ret; +} + +static esp_err_t zb_attribute_set_handler(const esp_zb_zcl_set_attr_value_message_t *message) { + if (!message) { + log_e("Empty message"); + } + if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Received message: error status(%d)", message->info.status); + } + + log_v( + "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 + ); + + // List through all Zigbee EPs and call the callback function, with the message + for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { + if (message->info.dst_endpoint == (*it)->getEndpoint()) { + if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY) { + (*it)->zbIdentify(message); //method zbIdentify implemented in the common EP class + } else { + (*it)->zbAttributeSet(message); //method zbAttributeSet must be implemented in specific EP class + } + } + } + return ESP_OK; +} + +static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_message_t *message) { + if (!message) { + log_e("Empty message"); + } + if (message->status != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Received message: error status(%d)", message->status); + } + log_v( + "Received report from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->src_address.u.short_addr, message->src_endpoint, + message->dst_endpoint, message->cluster + ); + // List through all Zigbee EPs and call the callback function, with the message + for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { + if (message->dst_endpoint == (*it)->getEndpoint()) { + (*it)->zbAttributeRead(message->cluster, &message->attribute); //method zbAttributeRead must be implemented in specific EP class + } + } + return ESP_OK; +} + +static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message) { + if (!message) { + log_e("Empty message"); + } + if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Received message: error status(%d)", message->info.status); + } + log_v( + "Read attribute response: from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->info.src_address.u.short_addr, + message->info.src_endpoint, message->info.dst_endpoint, message->info.cluster + ); + + for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { + if (message->info.dst_endpoint == (*it)->getEndpoint()) { + esp_zb_zcl_read_attr_resp_variable_t *variable = message->variables; + while (variable) { + log_v( + "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 (variable->status == ESP_ZB_ZCL_STATUS_SUCCESS) { + if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_BASIC) { + (*it)->zbReadBasicCluster(&variable->attribute); //method zbReadBasicCluster implemented in the common EP class + } else { + (*it)->zbAttributeRead(message->info.cluster, &variable->attribute); //method zbAttributeRead must be implemented in specific EP class + } + } + variable = variable->next; + } + } + } + return ESP_OK; +} + +static esp_err_t zb_configure_report_resp_handler(const esp_zb_zcl_cmd_config_report_resp_message_t *message) { + if (!message) { + log_e("Empty message"); + } + if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Received message: error status(%d)", message->info.status); + } + esp_zb_zcl_config_report_resp_variable_t *variable = message->variables; + while (variable) { + log_v( + "Configure report response: status(%d), cluster(0x%x), direction(0x%x), attribute(0x%x)", variable->status, message->info.cluster, variable->direction, + variable->attribute_id + ); + variable = variable->next; + } + return ESP_OK; +} + +static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_message_t *message) { + if (!message) { + log_e("Empty message"); + } + if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) { + log_e("Received message: error status(%d)", message->info.status); + } + log_v( + "Received default response: from address(0x%x), src_endpoint(%d) to dst_endpoint(%d), cluster(0x%x) with status 0x%x", + message->info.src_address.u.short_addr, message->info.src_endpoint, message->info.dst_endpoint, message->info.cluster, message->status_code + ); + return ESP_OK; +} + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp new file mode 100644 index 00000000000..841d9c7f122 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp @@ -0,0 +1,112 @@ +#include "ZigbeeColorDimmableLight.h" +#if SOC_IEEE802154_SUPPORTED + +ZigbeeColorDimmableLight::ZigbeeColorDimmableLight(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_COLOR_DIMMABLE_LIGHT_DEVICE_ID; + + esp_zb_color_dimmable_light_cfg_t light_cfg = ESP_ZB_DEFAULT_COLOR_DIMMABLE_LIGHT_CONFIG(); + _cluster_list = esp_zb_color_dimmable_light_clusters_create(&light_cfg); + _ep_config = { + .endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_COLOR_DIMMABLE_LIGHT_DEVICE_ID, .app_device_version = 0 + }; + + //set default values + _current_state = false; + _current_level = 255; + _current_red = 255; + _current_green = 255; + _current_blue = 255; +} + +uint16_t ZigbeeColorDimmableLight::getCurrentColorX() { + return (*(uint16_t *)esp_zb_zcl_get_attribute( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_X_ID + ) + ->data_p); +} + +uint16_t ZigbeeColorDimmableLight::getCurrentColorY() { + return (*(uint16_t *)esp_zb_zcl_get_attribute( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_Y_ID + ) + ->data_p); +} + +void ZigbeeColorDimmableLight::calculateRGB(uint16_t x, uint16_t y, uint8_t &red, uint8_t &green, uint8_t &blue) { + float r, g, b, color_x, color_y; + color_x = (float)x / 65535; + color_y = (float)y / 65535; + + float color_X = color_x / color_y; + float color_Z = (1 - color_x - color_y) / color_y; + + XYZ_TO_RGB(color_X, 1, color_Z, r, g, b); + + red = (uint8_t)(r * (float)255); + green = (uint8_t)(g * (float)255); + blue = (uint8_t)(b * (float)255); +} + +//set attribute method -> method overridden in child class +void ZigbeeColorDimmableLight::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) { + //check the data and call right method + 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) { + if (_current_state != *(bool *)message->attribute.data.value) { + _current_state = *(bool *)message->attribute.data.value; + lightChanged(); + } + return; + } else { + log_w("Received message ignored. Attribute ID: %d not supported for On/Off Light", message->attribute.id); + } + } else if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL) { + if (message->attribute.id == ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U8) { + if (_current_level != *(uint8_t *)message->attribute.data.value) { + _current_level = *(uint8_t *)message->attribute.data.value; + lightChanged(); + } + return; + } else { + log_w("Received message ignored. Attribute ID: %d not supported for Level Control", message->attribute.id); + //TODO: implement more attributes -> includes/zcl/esp_zigbee_zcl_level.h + } + } else if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL) { + if (message->attribute.id == ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_X_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) { + uint16_t light_color_x = (*(uint16_t *)message->attribute.data.value); + uint16_t light_color_y = getCurrentColorY(); + //calculate RGB from XY and call setColor() + uint8_t red, green, blue; + calculateRGB(light_color_x, light_color_y, red, green, blue); + _current_blue = blue; + _current_green = green; + _current_red = red; + lightChanged(); + return; + + } else if (message->attribute.id == ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_Y_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) { + uint16_t light_color_x = getCurrentColorX(); + uint16_t light_color_y = (*(uint16_t *)message->attribute.data.value); + //calculate RGB from XY and call setColor() + uint8_t red, green, blue; + calculateRGB(light_color_x, light_color_y, red, green, blue); + _current_blue = blue; + _current_green = green; + _current_red = red; + lightChanged(); + return; + } else { + log_w("Received message ignored. Attribute ID: %d not supported for Color Control", message->attribute.id); + } + } else { + log_w("Received message ignored. Cluster ID: %d not supported for Color dimmable Light", message->info.cluster); + } +} + +void ZigbeeColorDimmableLight::lightChanged() { + if (_on_light_change) { + _on_light_change(_current_state, _current_red, _current_green, _current_blue, _current_level); + } +} + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h new file mode 100644 index 00000000000..992c2573654 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h @@ -0,0 +1,41 @@ +/* Class of Zigbee On/Off Light endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_IEEE802154_SUPPORTED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +class ZigbeeColorDimmableLight : public ZigbeeEP { +public: + ZigbeeColorDimmableLight(uint8_t endpoint); + ~ZigbeeColorDimmableLight(); + + void onLightChange(void (*callback)(bool, uint8_t, uint8_t, uint8_t, uint8_t)) { + _on_light_change = callback; + } + void restoreLight() { + lightChanged(); + } + +private: + void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; + void calculateRGB(uint16_t x, uint16_t y, uint8_t &red, uint8_t &green, uint8_t &blue); + + uint16_t getCurrentColorX(); + uint16_t getCurrentColorY(); + + void lightChanged(); + //callback function to be called on light change (State, R, G, B, Level) + void (*_on_light_change)(bool, uint8_t, uint8_t, uint8_t, uint8_t); + + bool _current_state; + uint8_t _current_level; + uint16_t _current_red; + uint16_t _current_green; + uint16_t _current_blue; +}; + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp new file mode 100644 index 00000000000..c30599aadac --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp @@ -0,0 +1,403 @@ +#include "ZigbeeColorDimmerSwitch.h" +#if SOC_IEEE802154_SUPPORTED + +// Initialize the static instance pointer +ZigbeeColorDimmerSwitch *ZigbeeColorDimmerSwitch::_instance = nullptr; + +ZigbeeColorDimmerSwitch::ZigbeeColorDimmerSwitch(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_COLOR_DIMMER_SWITCH_DEVICE_ID; + _instance = this; // Set the static pointer to this instance + + esp_zb_color_dimmable_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_COLOR_DIMMABLE_SWITCH_CONFIG(); + _cluster_list = esp_zb_color_dimmable_switch_clusters_create(&switch_cfg); + + _ep_config = { + .endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_COLOR_DIMMER_SWITCH_DEVICE_ID, .app_device_version = 0 + }; +} + +void ZigbeeColorDimmerSwitch::calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y) { + // Convert RGB to XYZ + float r = (float)red / 255.0f; + float g = (float)green / 255.0f; + float b = (float)blue / 255.0f; + + float X, Y, Z; + RGB_TO_XYZ(r, g, b, X, Y, Z); + + // Convert XYZ to xy chromaticity coordinates + float color_x = X / (X + Y + Z); + float color_y = Y / (X + Y + Z); + + // Convert normalized xy to 16-bit values + x = (uint16_t)(color_x * 65535.0f); + y = (uint16_t)(color_y * 65535.0f); +} + +void ZigbeeColorDimmerSwitch::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + log_i("Bound successfully!"); + if (user_ctx) { + zb_device_params_t *light = (zb_device_params_t *)user_ctx; + log_i("The light originating from address(0x%x) on endpoint(%d)", light->short_addr, light->endpoint); + _instance->_bound_devices.push_back(light); + } + _is_bound = true; + } else { + log_e("Binding failed!"); + } +} + +void ZigbeeColorDimmerSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + log_d("Found light endpoint"); + esp_zb_zdo_bind_req_param_t bind_req; + zb_device_params_t *light = (zb_device_params_t *)malloc(sizeof(zb_device_params_t)); + light->endpoint = endpoint; + light->short_addr = addr; + esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr); + esp_zb_get_long_address(bind_req.src_address); + bind_req.src_endp = _endpoint; + bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF; + bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; + memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t)); + bind_req.dst_endp = endpoint; + bind_req.req_dst_addr = esp_zb_get_short_address(); + log_v("Try to bind on/off control of dimmable light"); + esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL); + bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL; + log_v("Try to bind level control of dimmable light"); + esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL); + bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL; + log_v("Try to bind color control of dimmable light"); + esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)light); + } else { + log_v("No color dimmable light endpoint found"); + } +} + +// find on_off light endpoint +void ZigbeeColorDimmerSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) { + uint16_t cluster_list[] = {ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, + ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL}; + esp_zb_zdo_match_desc_req_param_t color_dimmable_light_req = { + .dst_nwk_addr = cmd_req->dst_nwk_addr, + .addr_of_interest = cmd_req->addr_of_interest, + .profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .num_in_clusters = 3, + .num_out_clusters = 3, + .cluster_list = cluster_list, + }; + esp_zb_zdo_match_cluster(&color_dimmable_light_req, findCb, NULL); +} + +// Methods to control the light +void ZigbeeColorDimmerSwitch::lightToggle() { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; + log_i("Sending 'light toggle' command"); + //esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + //esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightToggle(uint16_t group_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; + log_i("Sending 'light toggle' command to group address 0x%x", group_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; + log_i("Sending 'light toggle' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOn() { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; + log_i("Sending 'light on' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOn(uint16_t group_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; + log_i("Sending 'light on' command to group address 0x%x", group_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; + log_i("Sending 'light on' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOff() { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; + log_i("Sending 'light off' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOff(uint16_t group_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; + log_i("Sending 'light off' command to group address 0x%x", group_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; + log_i("Sending 'light off' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) { + if (_is_bound) { + esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.effect_id = effect_id; + cmd_req.effect_variant = effect_variant; + log_i("Sending 'light off with effect' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_off_with_effect_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOnWithSceneRecall() { + if (_is_bound) { + esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + log_i("Sending 'light on with scene recall' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off) { + if (_is_bound) { + esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.on_off_control = on_off_control; //TODO: Test how it works, then maybe change API + cmd_req.on_time = time_on; + cmd_req.off_wait_time = time_off; + log_i("Sending 'light on with time off' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_on_off_on_with_timed_off_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level) { + if (_is_bound) { + esp_zb_zcl_move_to_level_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.level = level; + cmd_req.transition_time = 0xffff; + log_i("Sending 'set light level' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_level_move_to_level_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint16_t group_addr) { + if (_is_bound) { + esp_zb_zcl_move_to_level_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + cmd_req.level = level; + cmd_req.transition_time = 0xffff; + log_i("Sending 'set light level' command to group address 0x%x", group_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_level_move_to_level_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, uint16_t short_addr) { + if (_is_bound) { + esp_zb_zcl_move_to_level_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.level = level; + cmd_req.transition_time = 0xffff; + log_i("Sending 'set light level' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_level_move_to_level_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue) { + if (_is_bound) { + //Convert RGB to XY + uint16_t color_x, color_y; + calculateXY(red, green, blue, color_x, color_y); + + esp_zb_zcl_color_move_to_color_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.color_x = color_x; + cmd_req.color_y = color_y; + cmd_req.transition_time = 0; + log_i("Sending 'set light color' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_color_move_to_color_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint16_t group_addr) { + if (_is_bound) { + //Convert RGB to XY + uint16_t color_x, color_y; + calculateXY(red, green, blue, color_x, color_y); + + esp_zb_zcl_color_move_to_color_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + cmd_req.color_x = color_x; + cmd_req.color_y = color_y; + cmd_req.transition_time = 0; + log_i("Sending 'set light color' command to group address 0x%x", group_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_color_move_to_color_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, uint16_t short_addr) { + if (_is_bound) { + //Convert RGB to XY + uint16_t color_x, color_y; + calculateXY(red, green, blue, color_x, color_y); + + esp_zb_zcl_color_move_to_color_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.color_x = color_x; + cmd_req.color_y = color_y; + cmd_req.transition_time = 0; + log_i("Sending 'set light color' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_color_move_to_color_cmd_req(&cmd_req); + esp_zb_lock_release(); + } else { + log_e("Light not bound"); + } +} + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h new file mode 100644 index 00000000000..2263f3235ca --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h @@ -0,0 +1,60 @@ +/* Class of Zigbee On/Off Switch endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_IEEE802154_SUPPORTED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +class ZigbeeColorDimmerSwitch : public ZigbeeEP { +public: + ZigbeeColorDimmerSwitch(uint8_t endpoint); + ~ZigbeeColorDimmerSwitch(); + + // methods to control the color dimmable light + void lightToggle(); + void lightToggle(uint16_t group_addr); + void lightToggle(uint8_t endpoint, uint16_t short_addr); + + void lightOn(); + void lightOn(uint16_t group_addr); + void lightOn(uint8_t endpoint, uint16_t short_addr); + + void lightOff(); + void lightOff(uint16_t group_addr); + void lightOff(uint8_t endpoint, uint16_t short_addr); + + void lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant); + void lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off); + void lightOnWithSceneRecall(); + + void setLightLevel(uint8_t level); + void setLightLevel(uint8_t level, uint16_t group_addr); + void setLightLevel(uint8_t level, uint8_t endpoint, uint16_t short_addr); + + void setLightColor(uint8_t red, uint8_t green, uint8_t blue); + void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint16_t group_addr); + void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, uint16_t short_addr); + + void setLightColorSaturation(uint8_t value); + void setLightColorSaturation(uint8_t value, uint16_t group_addr); + void setLightColorSaturation(uint8_t value, uint8_t endpoint, uint16_t short_addr); + + void setLightColorHue(uint8_t value); + void setLightColorHue(uint8_t value, uint16_t group_addr); + void setLightColorHue(uint8_t value, uint8_t endpoint, uint16_t short_addr); + +private: + // save instance of the class in order to use it in static functions + static ZigbeeColorDimmerSwitch *_instance; + + void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req); + static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); + static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + + void calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y); +}; + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeLight.cpp b/libraries/Zigbee/src/ep/ZigbeeLight.cpp new file mode 100644 index 00000000000..0577ede1788 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeLight.cpp @@ -0,0 +1,35 @@ +#include "ZigbeeLight.h" +#if SOC_IEEE802154_SUPPORTED + +ZigbeeLight::ZigbeeLight(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID; + + esp_zb_on_off_light_cfg_t light_cfg = ESP_ZB_DEFAULT_ON_OFF_LIGHT_CONFIG(); + _cluster_list = esp_zb_on_off_light_clusters_create(&light_cfg); // use esp_zb_zcl_cluster_list_create() instead of esp_zb_on_off_light_clusters_create() + _ep_config = {.endpoint = _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}; +} + +//set attribute method -> method overridden in child class +void ZigbeeLight::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) { + //check the data and call right method + 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) { + _current_state = *(bool *)message->attribute.data.value; + lightChanged(); + } else { + log_w("Received message ignored. Attribute ID: %d not supported for On/Off Light", message->attribute.id); + } + } else { + log_w("Received message ignored. Cluster ID: %d not supported for On/Off Light", message->info.cluster); + } +} + +void ZigbeeLight::lightChanged() { + if (_on_light_change) { + _on_light_change(_current_state); + } else { + log_w("No callback function set for light change"); + } +} + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeLight.h b/libraries/Zigbee/src/ep/ZigbeeLight.h new file mode 100644 index 00000000000..32e4e8c9bdc --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeLight.h @@ -0,0 +1,33 @@ +/* Class of Zigbee On/Off Light endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_IEEE802154_SUPPORTED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +class ZigbeeLight : public ZigbeeEP { +public: + ZigbeeLight(uint8_t endpoint); + ~ZigbeeLight(); + + // Use tp set a cb function to be called on light change + void onLightChange(void (*callback)(bool)) { + _on_light_change = callback; + } + void restoreLight() { + lightChanged(); + } + +private: + void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; + //callback function to be called on light change + void (*_on_light_change)(bool); + void lightChanged(); + + bool _current_state; +}; + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp new file mode 100644 index 00000000000..9152732e376 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp @@ -0,0 +1,233 @@ +#include "ZigbeeSwitch.h" +#if SOC_IEEE802154_SUPPORTED + +// Initialize the static instance pointer +ZigbeeSwitch *ZigbeeSwitch::_instance = nullptr; + +ZigbeeSwitch::ZigbeeSwitch(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID; + _instance = this; // Set the static pointer to this instance + + esp_zb_on_off_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_ON_OFF_SWITCH_CONFIG(); + _cluster_list = esp_zb_on_off_switch_clusters_create(&switch_cfg); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID, .app_device_version = 0}; +} + +void ZigbeeSwitch::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + log_i("Bound successfully!"); + if (user_ctx) { + zb_device_params_t *light = (zb_device_params_t *)user_ctx; + log_i("The light originating from address(0x%x) on endpoint(%d)", light->short_addr, light->endpoint); + _instance->_bound_devices.push_back(light); + } + _is_bound = true; + } +} + +void ZigbeeSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + log_d("Found light endpoint"); + esp_zb_zdo_bind_req_param_t bind_req; + zb_device_params_t *light = (zb_device_params_t *)malloc(sizeof(zb_device_params_t)); + light->endpoint = endpoint; + light->short_addr = addr; + esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr); + esp_zb_get_long_address(bind_req.src_address); + bind_req.src_endp = _endpoint; //_dev_endpoint; + bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF; + bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; + memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t)); + bind_req.dst_endp = endpoint; + bind_req.req_dst_addr = esp_zb_get_short_address(); + log_i("Try to bind On/Off"); + esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)light); + } else { + log_d("No light endpoint found"); + } +} + +// find on_off light endpoint +void ZigbeeSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) { + uint16_t cluster_list[] = {ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF}; + esp_zb_zdo_match_desc_req_param_t on_off_req = { + .dst_nwk_addr = cmd_req->dst_nwk_addr, + .addr_of_interest = cmd_req->addr_of_interest, + .profile_id = ESP_ZB_AF_HA_PROFILE_ID, + .num_in_clusters = 1, + .num_out_clusters = 1, + .cluster_list = cluster_list, + }; + + esp_zb_zdo_match_cluster(&on_off_req, findCb, NULL); +} + +// Methods to control the light +void ZigbeeSwitch::lightToggle() { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; + log_i("Sending 'light toggle' command"); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightToggle(uint16_t group_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; + log_i("Sending 'light toggle' command to group address 0x%x", group_addr); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; + log_i("Sending 'light toggle' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightOn() { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; + log_i("Sending 'light on' command"); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightOn(uint16_t group_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; + log_i("Sending 'light on' command to group address 0x%x", group_addr); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; + log_i("Sending 'light on' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightOff() { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; + log_i("Sending 'light off' command"); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightOff(uint16_t group_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; + log_i("Sending 'light off' command to group address 0x%x", group_addr); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) { + if (_is_bound) { + esp_zb_zcl_on_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.zcl_basic_cmd.dst_endpoint = endpoint; + cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; + log_i("Sending 'light off' command to endpoint %d, address 0x%x", endpoint, short_addr); + esp_zb_zcl_on_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) { + if (_is_bound) { + esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.effect_id = effect_id; + cmd_req.effect_variant = effect_variant; + log_i("Sending 'light off with effect' command"); + esp_zb_zcl_on_off_off_with_effect_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +void ZigbeeSwitch::lightOnWithSceneRecall() { + if (_is_bound) { + esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + log_i("Sending 'light on with scene recall' command"); + esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} +void ZigbeeSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off) { + if (_is_bound) { + esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req; + cmd_req.zcl_basic_cmd.src_endpoint = _endpoint; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + cmd_req.on_off_control = on_off_control; //TODO: Test how it works, then maybe change API + cmd_req.on_time = time_on; + cmd_req.off_wait_time = time_off; + log_i("Sending 'light on with time off' command"); + esp_zb_zcl_on_off_on_with_timed_off_cmd_req(&cmd_req); + } else { + log_e("Light not bound"); + } +} + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.h b/libraries/Zigbee/src/ep/ZigbeeSwitch.h new file mode 100644 index 00000000000..bbc6c0a91dc --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.h @@ -0,0 +1,42 @@ +/* Class of Zigbee On/Off Switch endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_IEEE802154_SUPPORTED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +class ZigbeeSwitch : public ZigbeeEP { +public: + ZigbeeSwitch(uint8_t endpoint); + ~ZigbeeSwitch(); + + // methods to control the on/off light + void lightToggle(); + void lightToggle(uint16_t group_addr); + void lightToggle(uint8_t endpoint, uint16_t short_addr); + + void lightOn(); + void lightOn(uint16_t group_addr); + void lightOn(uint8_t endpoint, uint16_t short_addr); + + void lightOff(); + void lightOff(uint16_t group_addr); + void lightOff(uint8_t endpoint, uint16_t short_addr); + + void lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant); + void lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off); + void lightOnWithSceneRecall(); + +private: + // save instance of the class in order to use it in static functions + static ZigbeeSwitch *_instance; + + void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req); + static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); + static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); +}; + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp new file mode 100644 index 00000000000..e0dba03da5c --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp @@ -0,0 +1,93 @@ +#include "ZigbeeTempSensor.h" +#if SOC_IEEE802154_SUPPORTED + +ZigbeeTempSensor::ZigbeeTempSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID; + + esp_zb_temperature_sensor_cfg_t temp_sensor_cfg = ESP_ZB_DEFAULT_TEMPERATURE_SENSOR_CONFIG(); + _cluster_list = esp_zb_temperature_sensor_clusters_create(&temp_sensor_cfg); + + _ep_config = { + .endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID, .app_device_version = 0 + }; +} + +static int16_t zb_temperature_to_s16(float temp) { + return (int16_t)(temp * 100); +} + +void ZigbeeTempSensor::setMinMaxValue(float min, float max) { + int16_t zb_min = zb_temperature_to_s16(min); + int16_t zb_max = zb_temperature_to_s16(max); + esp_zb_attribute_list_t *temp_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_update_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, (void *)&zb_min); + esp_zb_cluster_update_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, (void *)&zb_max); +} + +void ZigbeeTempSensor::setTolerance(float tolerance) { + // Convert tolerance to ZCL uint16_t + uint16_t zb_tolerance = (uint16_t)(tolerance * 100); + esp_zb_attribute_list_t *temp_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_temperature_meas_cluster_add_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); +} + +void ZigbeeTempSensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { + esp_zb_zcl_reporting_info_t reporting_info = { + .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV, + .ep = _endpoint, + .cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, + .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, + .attr_id = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, + .u = + { + .send_info = + { + .min_interval = min_interval, + .max_interval = max_interval, + .delta = + { + .u16 = (uint16_t)(delta * 100), // Convert delta to ZCL uint16_t + }, + .def_min_interval = min_interval, + .def_max_interval = max_interval, + }, + }, + .dst = + { + .profile_id = ESP_ZB_AF_HA_PROFILE_ID, + }, + .manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC, + }; + esp_zb_zcl_update_reporting_info(&reporting_info); +} + +void ZigbeeTempSensor::setTemperature(float temperature) { + int16_t zb_temperature = zb_temperature_to_s16(temperature); + log_v("Updating temperature sensor value..."); + /* Update temperature sensor measured value */ + log_d("Setting temperature to %d", zb_temperature); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &zb_temperature, false + ); + esp_zb_lock_release(); +} + +void ZigbeeTempSensor::reportTemperature() { + /* Send report attributes command */ + esp_zb_zcl_report_attr_cmd_t report_attr_cmd; + report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID; + report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd); + esp_zb_lock_release(); + log_v("Temperature report sent"); +} + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h new file mode 100644 index 00000000000..22317721fc4 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h @@ -0,0 +1,30 @@ +/* Class of Zigbee Temperature sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_IEEE802154_SUPPORTED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +class ZigbeeTempSensor : public ZigbeeEP { +public: + ZigbeeTempSensor(uint8_t endpoint); + ~ZigbeeTempSensor(); + + // Set the temperature value in 0,01°C + void setTemperature(float value); + + // Set the min and max value for the temperature sensor in 0,01°C + void setMinMaxValue(float min, float max); + + // Set the tolerance value for the temperature sensor in 0,01°C + void setTolerance(float tolerance); + + // Set the reporting interval for temperature measurement in seconds and delta (temp change in 0,01 °C) + void setReporting(uint16_t min_interval, uint16_t max_interval, float delta); + void reportTemperature(); +}; + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp new file mode 100644 index 00000000000..28ed2a70cd2 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp @@ -0,0 +1,205 @@ +#include "ZigbeeThermostat.h" +#if SOC_IEEE802154_SUPPORTED + +static float zb_s16_to_temperature(int16_t value) { + return 1.0 * value / 100; +} + +// Initialize the static instance of the class +ZigbeeThermostat *ZigbeeThermostat::_instance = nullptr; + +ZigbeeThermostat::ZigbeeThermostat(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_THERMOSTAT_DEVICE_ID; + _instance = this; // Set the static pointer to this instance + + //use custom config to avoid narrowing error -> must be fixed in zigbee-sdk + esp_zb_thermostat_cfg_t thermostat_cfg = ZB_DEFAULT_THERMOSTAT_CONFIG(); + + //use custom cluster creating to accept reportings from temperature sensor + _cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_attribute_list_t *basic_cluster = esp_zb_basic_cluster_create(&(thermostat_cfg.basic_cfg)); + esp_zb_cluster_list_add_basic_cluster(_cluster_list, basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(_cluster_list, esp_zb_identify_cluster_create(&(thermostat_cfg.identify_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(_cluster_list, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE); + esp_zb_cluster_list_add_thermostat_cluster(_cluster_list, esp_zb_thermostat_cluster_create(&(thermostat_cfg.thermostat_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + /* Add temperature measurement cluster for attribute reporting */ + esp_zb_cluster_list_add_temperature_meas_cluster(_cluster_list, esp_zb_temperature_meas_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_THERMOSTAT_DEVICE_ID, .app_device_version = 0}; +} + +void ZigbeeThermostat::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) { + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + if (user_ctx) { + zb_device_params_t *sensor = (zb_device_params_t *)user_ctx; + log_i("The temperature sensor originating from address(0x%x) on endpoint(%d)", sensor->short_addr, sensor->endpoint); + _instance->_bound_devices.push_back(sensor); + } else { + log_v("Local binding success"); + } + _is_bound = true; + } else { + log_e("Binding failed!"); + } +} + +void ZigbeeThermostat::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + log_i("Found temperature sensor"); + esp_zb_zdo_bind_req_param_t bind_req; + /* Store the information of the remote device */ + zb_device_params_t *sensor = (zb_device_params_t *)malloc(sizeof(zb_device_params_t)); + sensor->endpoint = endpoint; + sensor->short_addr = addr; + esp_zb_ieee_address_by_short(sensor->short_addr, sensor->ieee_addr); + log_d("Temperature sensor found: short address(0x%x), endpoint(%d)", sensor->short_addr, sensor->endpoint); + + /* 1. Send binding request to the sensor */ + bind_req.req_dst_addr = addr; + log_d("Request temperature sensor to bind us"); + + /* populate the src information of the binding */ + memcpy(bind_req.src_address, sensor->ieee_addr, sizeof(esp_zb_ieee_addr_t)); + bind_req.src_endp = endpoint; + bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + log_d("Bind temperature sensor"); + + /* populate the dst information of the binding */ + bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; + esp_zb_get_long_address(bind_req.dst_address_u.addr_long); + bind_req.dst_endp = _endpoint; + + log_i("Request temperature sensor to bind us"); + esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL); + + /* 2. Send binding request to self */ + bind_req.req_dst_addr = esp_zb_get_short_address(); + + /* populate the src information of the binding */ + esp_zb_get_long_address(bind_req.src_address); + bind_req.src_endp = _endpoint; + bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + /* populate the dst information of the binding */ + bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; + memcpy(bind_req.dst_address_u.addr_long, sensor->ieee_addr, sizeof(esp_zb_ieee_addr_t)); + bind_req.dst_endp = endpoint; + + log_i("Bind temperature sensor"); + esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)sensor); + } +} + +void ZigbeeThermostat::findEndpoint(esp_zb_zdo_match_desc_req_param_t *param) { + uint16_t cluster_list[] = {ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT}; + param->profile_id = ESP_ZB_AF_HA_PROFILE_ID; + param->num_in_clusters = 1; + param->num_out_clusters = 0; + param->cluster_list = cluster_list; + esp_zb_zdo_match_cluster(param, findCb, NULL); +} + +void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) { + static uint8_t read_config = 0; + if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT) { + if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { + int16_t value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; + if (_on_temp_recieve) { + _on_temp_recieve(zb_s16_to_temperature(value)); + } + } + if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { + int16_t min_value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; + _min_temp = zb_s16_to_temperature(min_value); + read_config++; + } + if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) { + int16_t max_value = attribute->data.value ? *(int16_t *)attribute->data.value : 0; + _max_temp = zb_s16_to_temperature(max_value); + read_config++; + } + if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) { + uint16_t tolerance = attribute->data.value ? *(uint16_t *)attribute->data.value : 0; + _tolerance = 1.0 * tolerance / 100; + read_config++; + } + if (read_config == 3) { + read_config = 0; + xSemaphoreGive(lock); + } + } +} + +void ZigbeeThermostat::getTemperature() { + /* Send "read attributes" command to the bound sensor */ + esp_zb_zcl_read_attr_cmd_t read_req; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID}; + read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_field = attributes; + + log_i("Sending 'read temperature' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); +} + +void ZigbeeThermostat::getSensorSettings() { + /* Send "read attributes" command to the bound sensor */ + esp_zb_zcl_read_attr_cmd_t read_req; + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + read_req.zcl_basic_cmd.src_endpoint = _endpoint; + read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + uint16_t attributes[] = { + ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID + }; + read_req.attr_number = ZB_ARRAY_LENTH(attributes); + read_req.attr_field = attributes; + + log_i("Sending 'read temperature' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); + + //Take semaphore to wait for response of all attributes + if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) { + log_e("Error while reading attributes"); + return; + } else { + //Call the callback function when all attributes are read + _on_config_recieve(_min_temp, _max_temp, _tolerance); + } +} + +void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t max_interval, float delta) { + /* Send "configure report attribute" command to the bound sensor */ + esp_zb_zcl_config_report_cmd_t report_cmd; + report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; + report_cmd.zcl_basic_cmd.src_endpoint = _endpoint; + report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; + + int16_t report_change = (int16_t)delta * 100; + esp_zb_zcl_config_report_record_t records[] = { + { + .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV, + .attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, + .attrType = ESP_ZB_ZCL_ATTR_TYPE_S16, + .min_interval = min_interval, + .max_interval = max_interval, + .reportable_change = &report_change, + }, + }; + report_cmd.record_number = ZB_ARRAY_LENTH(records); + report_cmd.record_field = records; + + log_i("Sending 'configure reporting' command"); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_config_report_cmd_req(&report_cmd); + esp_zb_lock_release(); +} + +#endif //SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.h b/libraries/Zigbee/src/ep/ZigbeeThermostat.h new file mode 100644 index 00000000000..7d63cd9f726 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.h @@ -0,0 +1,64 @@ +/* Class of Zigbee Temperature sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_IEEE802154_SUPPORTED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +//define the thermostat configuration to avoid narrowing conversion issue in zigbee-sdk +#define ZB_DEFAULT_THERMOSTAT_CONFIG() \ + { \ + .basic_cfg = \ + { \ + .zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE, \ + .power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE, \ + }, \ + .identify_cfg = \ + { \ + .identify_time = ESP_ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE, \ + }, \ + .thermostat_cfg = { \ + .local_temperature = (int16_t)ESP_ZB_ZCL_THERMOSTAT_LOCAL_TEMPERATURE_DEFAULT_VALUE, \ + .occupied_cooling_setpoint = ESP_ZB_ZCL_THERMOSTAT_OCCUPIED_COOLING_SETPOINT_DEFAULT_VALUE, \ + .occupied_heating_setpoint = ESP_ZB_ZCL_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_DEFAULT_VALUE, \ + .control_sequence_of_operation = ESP_ZB_ZCL_THERMOSTAT_CONTROL_SEQ_OF_OPERATION_DEFAULT_VALUE, \ + .system_mode = ESP_ZB_ZCL_THERMOSTAT_CONTROL_SYSTEM_MODE_DEFAULT_VALUE, \ + }, \ + } +class ZigbeeThermostat : public ZigbeeEP { +public: + ZigbeeThermostat(uint8_t endpoint); + ~ZigbeeThermostat(); + + void onTempRecieve(void (*callback)(float)) { + _on_temp_recieve = callback; + } + void onConfigRecieve(void (*callback)(float, float, float)) { + _on_config_recieve = callback; + } + + void getTemperature(); + void getSensorSettings(); + void setTemperatureReporting(uint16_t min_interval, uint16_t max_interval, float delta); + +private: + // save instance of the class in order to use it in static functions + static ZigbeeThermostat *_instance; + + void (*_on_temp_recieve)(float); + void (*_on_config_recieve)(float, float, float); + float _min_temp; + float _max_temp; + float _tolerance; + + void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req); + static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx); + static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); + + void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) override; +}; + +#endif //SOC_IEEE802154_SUPPORTED From b067cd6d7f92bd171546a42ec28d646c52a6053c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:25:15 +0200 Subject: [PATCH 033/406] fix(example): Skip zigbee build for P4 --- libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json | 3 ++- libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json | 3 ++- libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json | 3 ++- libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json | 3 ++- libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json | 3 ++- libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json | 3 ++- libraries/Zigbee/examples/Zigbee_Thermostat/ci.json | 3 ++- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json index 3aaf44eb376..f6e4a17c15d 100644 --- a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json @@ -11,6 +11,7 @@ "esp32": false, "esp32c3": false, "esp32s2": false, - "esp32s3": false + "esp32s3": false, + "esp32p4": false } } diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json index c916121b991..e51a291ca49 100644 --- a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json @@ -11,6 +11,7 @@ "esp32": false, "esp32c3": false, "esp32s2": false, - "esp32s3": false + "esp32s3": false, + "esp32p4": false } } diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json index 3aaf44eb376..f6e4a17c15d 100644 --- a/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json @@ -11,6 +11,7 @@ "esp32": false, "esp32c3": false, "esp32s2": false, - "esp32s3": false + "esp32s3": false, + "esp32p4": false } } diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json index c916121b991..e51a291ca49 100644 --- a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json @@ -11,6 +11,7 @@ "esp32": false, "esp32c3": false, "esp32s2": false, - "esp32s3": false + "esp32s3": false, + "esp32p4": false } } diff --git a/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json b/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json index 3aaf44eb376..f6e4a17c15d 100644 --- a/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json @@ -11,6 +11,7 @@ "esp32": false, "esp32c3": false, "esp32s2": false, - "esp32s3": false + "esp32s3": false, + "esp32p4": false } } diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json index 3aaf44eb376..f6e4a17c15d 100644 --- a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json @@ -11,6 +11,7 @@ "esp32": false, "esp32c3": false, "esp32s2": false, - "esp32s3": false + "esp32s3": false, + "esp32p4": false } } diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json b/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json index c916121b991..e51a291ca49 100644 --- a/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json @@ -11,6 +11,7 @@ "esp32": false, "esp32c3": false, "esp32s2": false, - "esp32s3": false + "esp32s3": false, + "esp32p4": false } } From c5047286a1d743e62d441b8bf23cf5aeda74bac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 2 Oct 2024 18:40:04 +0200 Subject: [PATCH 034/406] fix(example): Use requires instead of target in ci.json --- .../examples/Zigbee_Color_Dimmable_Light/ci.json | 10 +++------- .../Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json | 10 +++------- libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json | 10 +++------- libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json | 10 +++------- libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json | 10 +++------- .../Zigbee/examples/Zigbee_Temperature_Sensor/ci.json | 10 +++------- libraries/Zigbee/examples/Zigbee_Thermostat/ci.json | 10 +++------- 7 files changed, 21 insertions(+), 49 deletions(-) diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json index f6e4a17c15d..d3573967de0 100644 --- a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json @@ -7,11 +7,7 @@ "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" ] }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false, - "esp32p4": false - } + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json index e51a291ca49..3a5d7026228 100644 --- a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json @@ -7,11 +7,7 @@ "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" ] }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false, - "esp32p4": false - } + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json index f6e4a17c15d..d3573967de0 100644 --- a/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json @@ -7,11 +7,7 @@ "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" ] }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false, - "esp32p4": false - } + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json index e51a291ca49..3a5d7026228 100644 --- a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json @@ -7,11 +7,7 @@ "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" ] }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false, - "esp32p4": false - } + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json b/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json index f6e4a17c15d..d3573967de0 100644 --- a/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json @@ -7,11 +7,7 @@ "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" ] }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false, - "esp32p4": false - } + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json index f6e4a17c15d..d3573967de0 100644 --- a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json @@ -7,11 +7,7 @@ "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" ] }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false, - "esp32p4": false - } + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json b/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json index e51a291ca49..3a5d7026228 100644 --- a/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json @@ -7,11 +7,7 @@ "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" ] }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false, - "esp32p4": false - } + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } From c3aa74f60ab0d6377d17d5ef14a8ddd08c380be1 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 2 Oct 2024 19:26:33 +0300 Subject: [PATCH 035/406] fix(spiram): Fix OPI PSRAM init --- cores/esp32/esp32-hal-misc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index 1fb1d2af9df..0bce548bdd2 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -253,13 +253,11 @@ extern bool btInUse(); #endif #if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM -#ifndef CONFIG_SPIRAM_BOOT_INIT ESP_SYSTEM_INIT_FN(init_psram_new, CORE, BIT(0), 99) { psramInit(); return ESP_OK; } #endif -#endif void initArduino() { //init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz) From 01b256ca1cd6d341b53758591eaa905818ff4aaa Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 2 Oct 2024 21:08:49 +0300 Subject: [PATCH 036/406] fix(usb): Enable TinyUSB mode for ESP32-P4 --- .github/scripts/sketch_utils.sh | 2 +- boards.txt | 27 ++++++++++++++++++++++----- platform.txt | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.github/scripts/sketch_utils.sh b/.github/scripts/sketch_utils.sh index eae5c139428..b19a0ab67a9 100755 --- a/.github/scripts/sketch_utils.sh +++ b/.github/scripts/sketch_utils.sh @@ -91,7 +91,7 @@ function build_sketch(){ # build_sketch [ex esp32c3_opts="PartitionScheme=huge_app,FlashMode=dio" esp32c6_opts="PartitionScheme=huge_app,FlashMode=dio" esp32h2_opts="PartitionScheme=huge_app,FlashMode=dio" - esp32p4_opts="PartitionScheme=huge_app,FlashMode=dio" + esp32p4_opts="PartitionScheme=huge_app,FlashMode=dio,USBMode=default" # Select the common part of the FQBN based on the target. The rest will be # appended depending on the passed options. diff --git a/boards.txt b/boards.txt index 0ff823bd4e0..51b4adfd868 100644 --- a/boards.txt +++ b/boards.txt @@ -212,21 +212,38 @@ esp32p4.menu.JTAGAdapter.bridge=ESP USB Bridge esp32p4.menu.JTAGAdapter.bridge.build.openocdscript=esp32p4-bridge.cfg esp32p4.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 -esp32p4.menu.CDCOnBoot.default=Disabled -esp32p4.menu.CDCOnBoot.default.build.cdc_on_boot=0 -esp32p4.menu.CDCOnBoot.cdc=Enabled -esp32p4.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 - esp32p4.menu.PSRAM.disabled=Disabled esp32p4.menu.PSRAM.disabled.build.defines= esp32p4.menu.PSRAM.enabled=Enabled esp32p4.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +esp32p4.menu.USBMode.hwcdc=Hardware CDC and JTAG +esp32p4.menu.USBMode.hwcdc.build.usb_mode=1 +esp32p4.menu.USBMode.default=USB-OTG (TinyUSB) +esp32p4.menu.USBMode.default.build.usb_mode=0 + esp32p4.menu.CDCOnBoot.default=Disabled esp32p4.menu.CDCOnBoot.default.build.cdc_on_boot=0 esp32p4.menu.CDCOnBoot.cdc=Enabled esp32p4.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +esp32p4.menu.MSCOnBoot.default=Disabled +esp32p4.menu.MSCOnBoot.default.build.msc_on_boot=0 +esp32p4.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +esp32p4.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +esp32p4.menu.DFUOnBoot.default=Disabled +esp32p4.menu.DFUOnBoot.default.build.dfu_on_boot=0 +esp32p4.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +esp32p4.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +esp32p4.menu.UploadMode.default=UART0 / Hardware CDC +esp32p4.menu.UploadMode.default.upload.use_1200bps_touch=false +esp32p4.menu.UploadMode.default.upload.wait_for_upload_port=false +esp32p4.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +esp32p4.menu.UploadMode.cdc.upload.use_1200bps_touch=true +esp32p4.menu.UploadMode.cdc.upload.wait_for_upload_port=true + esp32p4.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) esp32p4.menu.PartitionScheme.default.build.partitions=default esp32p4.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) diff --git a/platform.txt b/platform.txt index b9c31d4337f..8d918d3dea7 100644 --- a/platform.txt +++ b/platform.txt @@ -84,7 +84,7 @@ build.extra_flags.esp32c2=-DARDUINO_USB_CDC_ON_BOOT=0 build.extra_flags.esp32c3=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} build.extra_flags.esp32c6=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} build.extra_flags.esp32h2=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} -build.extra_flags.esp32p4=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} +build.extra_flags.esp32p4=-DARDUINO_USB_MODE={build.usb_mode} -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} -DARDUINO_USB_MSC_ON_BOOT={build.msc_on_boot} -DARDUINO_USB_DFU_ON_BOOT={build.dfu_on_boot} # This can be overriden in boards.txt build.zigbee_mode= From ea50cf6f5f83ed4ea4048ada08728c9827609a49 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 2 Oct 2024 22:18:17 +0300 Subject: [PATCH 037/406] fix(spiram): Fix OPI PSRAM init (#10406) --- cores/esp32/esp32-hal-misc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c index dd7a87a4f22..86140144613 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -251,13 +251,11 @@ extern bool btInUse(); #endif #if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM -#ifndef CONFIG_SPIRAM_BOOT_INIT ESP_SYSTEM_INIT_FN(init_psram_new, BIT(0), 99) { psramInit(); return ESP_OK; } #endif -#endif void initArduino() { //init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz) From 157b4c864388fe8461471f2abaf85da70259537f Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 2 Oct 2024 22:26:26 +0300 Subject: [PATCH 038/406] IDF release/v5.3 (#10403) IDF release/v5.3 707d097b --- package/package_esp32_index.template.json | 68 +++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 4df82b26bee..ea85072b9cb 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -42,7 +42,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-4d0db704" + "version": "idf-release_v5.3-707d097b" }, { "packager": "esp32", @@ -95,63 +95,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-4d0db704", + "version": "idf-release_v5.3-707d097b", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", - "size": "360076736" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", + "size": "399730073" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", - "size": "360076736" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", + "size": "399730073" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", - "size": "360076736" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", + "size": "399730073" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", - "size": "360076736" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", + "size": "399730073" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", - "size": "360076736" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", + "size": "399730073" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", - "size": "360076736" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", + "size": "399730073" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", - "size": "360076736" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", + "size": "399730073" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-4d0db704.zip", - "checksum": "SHA-256:645b7579d22e7de73c87cce1d52629f9780de9f18be5b5b066ac0f2c210e9bef", - "size": "360076736" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", + "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", + "size": "399730073" } ] }, From 733373a049d8a06fab00628bcae585550fac6d07 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 3 Oct 2024 03:37:44 -0300 Subject: [PATCH 039/406] Update FreeRTOS Symbols in OThreadCLI (#10412) * Update OThreadCLI.cpp * feat(openthread): change FreeRTOS names and types * feat(openthread): change FreeRTOS names and types QueueHandle_t instead of xQueueHandle --- libraries/OpenThread/README.md | 2 +- libraries/OpenThread/src/OThreadCLI.cpp | 6 +++--- libraries/OpenThread/src/OThreadCLI.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/OpenThread/README.md b/libraries/OpenThread/README.md index f8ea94f1cf5..cd9deb9ebf6 100644 --- a/libraries/OpenThread/README.md +++ b/libraries/OpenThread/README.md @@ -19,7 +19,7 @@ Below are the details of the class: ```cpp class OpenThreadCLI : public Stream { private: - static size_t setBuffer(xQueueHandle &queue, size_t len); + static size_t setBuffer(QueueHandle_t &queue, size_t len); bool otStarted = false; public: diff --git a/libraries/OpenThread/src/OThreadCLI.cpp b/libraries/OpenThread/src/OThreadCLI.cpp index cb29584c17b..9190f09bc6b 100644 --- a/libraries/OpenThread/src/OThreadCLI.cpp +++ b/libraries/OpenThread/src/OThreadCLI.cpp @@ -21,8 +21,8 @@ static TaskHandle_t s_cli_task = NULL; static TaskHandle_t s_console_cli_task = NULL; -static xQueueHandle rx_queue = NULL; -static xQueueHandle tx_queue = NULL; +static QueueHandle_t rx_queue = NULL; +static QueueHandle_t tx_queue = NULL; static esp_openthread_platform_config_t ot_native_config; static TaskHandle_t s_ot_task = NULL; @@ -389,7 +389,7 @@ size_t OpenThreadCLI::write(uint8_t c) { return 1; } -size_t OpenThreadCLI::setBuffer(xQueueHandle &queue, size_t queue_len) { +size_t OpenThreadCLI::setBuffer(QueueHandle_t &queue, size_t queue_len) { if (queue) { vQueueDelete(queue); queue = NULL; diff --git a/libraries/OpenThread/src/OThreadCLI.h b/libraries/OpenThread/src/OThreadCLI.h index 3d18589a07d..689b4a5672b 100644 --- a/libraries/OpenThread/src/OThreadCLI.h +++ b/libraries/OpenThread/src/OThreadCLI.h @@ -22,7 +22,7 @@ typedef std::function OnReceiveCb_t; class OpenThreadCLI : public Stream { private: - static size_t setBuffer(xQueueHandle &queue, size_t len); + static size_t setBuffer(QueueHandle_t &queue, size_t len); bool otStarted = false; public: From 341dc18079245c62dc66d397825058a5b59805fd Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 3 Oct 2024 13:47:24 +0300 Subject: [PATCH 040/406] fix(usb): Add support for HighSpeed USB This commit adds support for HighSpeed USB as present on ESP32-P4 --- cores/esp32/USBCDC.cpp | 2 +- cores/esp32/USBMSC.cpp | 2 +- cores/esp32/esp32-hal-tinyusb.c | 10 +++++++++- cores/esp32/esp32-hal-tinyusb.h | 8 ++++++++ libraries/USB/src/USBHID.cpp | 2 +- libraries/USB/src/USBMIDI.cpp | 2 +- libraries/USB/src/USBVendor.cpp | 11 +++++++---- libraries/USB/src/USBVendor.h | 2 +- 8 files changed, 29 insertions(+), 10 deletions(-) diff --git a/cores/esp32/USBCDC.cpp b/cores/esp32/USBCDC.cpp index 2689086013a..795a17dc0b8 100644 --- a/cores/esp32/USBCDC.cpp +++ b/cores/esp32/USBCDC.cpp @@ -31,7 +31,7 @@ USBCDC *devices[MAX_USB_CDC_DEVICES] = {NULL, NULL}; static uint16_t load_cdc_descriptor(uint8_t *dst, uint8_t *itf) { uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC"); uint8_t descriptor[TUD_CDC_DESC_LEN] = {// Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64) + TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, CFG_TUD_ENDOINT_SIZE, 0x03, 0x84, CFG_TUD_ENDOINT_SIZE) }; *itf += 2; memcpy(dst, descriptor, TUD_CDC_DESC_LEN); diff --git a/cores/esp32/USBMSC.cpp b/cores/esp32/USBMSC.cpp index eeaf3026535..aeb79883f0d 100644 --- a/cores/esp32/USBMSC.cpp +++ b/cores/esp32/USBMSC.cpp @@ -24,7 +24,7 @@ extern "C" uint16_t tusb_msc_load_descriptor(uint8_t *dst, uint8_t *itf) { uint8_t ep_num = tinyusb_get_free_duplex_endpoint(); TU_VERIFY(ep_num != 0); uint8_t descriptor[TUD_MSC_DESC_LEN] = {// Interface number, string index, EP Out & EP In address, EP size - TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64) + TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), CFG_TUD_ENDOINT_SIZE) }; *itf += 1; memcpy(dst, descriptor, TUD_MSC_DESC_LEN); diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index 4247a299df0..c69fca08fc7 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -131,7 +131,11 @@ esp_err_t init_usb_hal(bool external_phy) { .controller = USB_PHY_CTRL_OTG, .target = USB_PHY_TARGET_INT, .otg_mode = USB_OTG_MODE_DEVICE, +#if CONFIG_IDF_TARGET_ESP32P4 + .otg_speed = USB_PHY_SPEED_HIGH, +#else .otg_speed = USB_PHY_SPEED_FULL, +#endif .ext_io_conf = NULL, .otg_io_conf = NULL, }; @@ -169,7 +173,11 @@ void deinit_usb_hal() { esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) { init_usb_hal(config->external_phy); - if (!tusb_init()) { +#if CONFIG_IDF_TARGET_ESP32P4 + if (!tud_init(1)) { +#else + if (!tud_init(0)) { +#endif log_e("Can't initialize the TinyUSB stack."); return ESP_FAIL; } diff --git a/cores/esp32/esp32-hal-tinyusb.h b/cores/esp32/esp32-hal-tinyusb.h index 9e9d044f80e..0b42760e69f 100644 --- a/cores/esp32/esp32-hal-tinyusb.h +++ b/cores/esp32/esp32-hal-tinyusb.h @@ -31,6 +31,14 @@ extern "C" { #define USB_ESPRESSIF_VID 0x303A #define USB_STRING_DESCRIPTOR_ARRAY_SIZE 10 +#ifndef CFG_TUD_ENDOINT_SIZE +#if CONFIG_IDF_TARGET_ESP32P4 +#define CFG_TUD_ENDOINT_SIZE 512 +#else +#define CFG_TUD_ENDOINT_SIZE 64 +#endif +#endif + typedef struct { uint16_t vid; uint16_t pid; diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index 75f37ef5df3..4bc555b8e30 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -206,7 +206,7 @@ extern "C" uint16_t tusb_hid_load_descriptor(uint8_t *dst, uint8_t *itf) { uint8_t descriptor[TUD_HID_INOUT_DESC_LEN] = { // HID Input & Output descriptor // Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval - TUD_HID_INOUT_DESCRIPTOR(*itf, str_index, tinyusb_interface_protocol, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), 64, 1) + TUD_HID_INOUT_DESCRIPTOR(*itf, str_index, tinyusb_interface_protocol, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE, 1) }; *itf += 1; memcpy(dst, descriptor, TUD_HID_INOUT_DESC_LEN); diff --git a/libraries/USB/src/USBMIDI.cpp b/libraries/USB/src/USBMIDI.cpp index cfc40e7b154..8a9571855e1 100644 --- a/libraries/USB/src/USBMIDI.cpp +++ b/libraries/USB/src/USBMIDI.cpp @@ -24,7 +24,7 @@ extern "C" uint16_t tusb_midi_load_descriptor(uint8_t *dst, uint8_t *itf) { uint8_t ep_out = tinyusb_get_free_out_endpoint(); TU_VERIFY(ep_out != 0); uint8_t descriptor[TUD_MIDI_DESC_LEN] = { - TUD_MIDI_DESCRIPTOR(*itf, str_index, ep_out, (uint8_t)(0x80 | ep_in), 64), + TUD_MIDI_DESCRIPTOR(*itf, str_index, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE), }; *itf += 2; memcpy(dst, descriptor, TUD_MIDI_DESC_LEN); diff --git a/libraries/USB/src/USBVendor.cpp b/libraries/USB/src/USBVendor.cpp index 293d5866945..70fac5770ae 100644 --- a/libraries/USB/src/USBVendor.cpp +++ b/libraries/USB/src/USBVendor.cpp @@ -24,7 +24,7 @@ esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, i static USBVendor *_Vendor = NULL; static QueueHandle_t rx_queue = NULL; -static uint8_t USB_VENDOR_ENDPOINT_SIZE = 64; +static uint16_t USB_VENDOR_ENDPOINT_SIZE = CFG_TUD_ENDOINT_SIZE; uint16_t tusb_vendor_load_descriptor(uint8_t *dst, uint8_t *itf) { uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB Vendor"); @@ -68,10 +68,13 @@ extern "C" bool tinyusb_vendor_control_request_cb(uint8_t rhport, uint8_t stage, return false; } -USBVendor::USBVendor(uint8_t endpoint_size) : itf(0), cb(NULL) { +USBVendor::USBVendor(uint16_t endpoint_size) : itf(0), cb(NULL) { if (!_Vendor) { _Vendor = this; - if (endpoint_size <= 64) { + if (endpoint_size == 0) { + endpoint_size = CFG_TUD_ENDOINT_SIZE; + } + if (endpoint_size <= CFG_TUD_ENDOINT_SIZE) { USB_VENDOR_ENDPOINT_SIZE = endpoint_size; } tinyusb_enable_interface(USB_INTERFACE_VENDOR, TUD_VENDOR_DESC_LEN, tusb_vendor_load_descriptor); @@ -97,7 +100,7 @@ size_t USBVendor::setRxBufferSize(size_t rx_queue_len) { } void USBVendor::begin() { - setRxBufferSize(256); //default if not preset + setRxBufferSize(512); //default if not preset } void USBVendor::end() { diff --git a/libraries/USB/src/USBVendor.h b/libraries/USB/src/USBVendor.h index e3e22281939..4990e466321 100644 --- a/libraries/USB/src/USBVendor.h +++ b/libraries/USB/src/USBVendor.h @@ -74,7 +74,7 @@ class USBVendor : public Stream { arduino_usb_vendor_control_request_handler_t cb; public: - USBVendor(uint8_t endpoint_size = 64); + USBVendor(uint16_t endpoint_size = 0); void begin(void); void end(void); size_t setRxBufferSize(size_t); From 6d6a8f8d3207c0f34cb6ad66b92a071fe1215d0b Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 3 Oct 2024 16:35:39 +0300 Subject: [PATCH 041/406] IDF release/v5.3 707d097b (#10416) --- package/package_esp32_index.template.json | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index ea85072b9cb..ea66c5a816d 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -101,57 +101,57 @@ "host": "i686-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", - "size": "399730073" + "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", + "size": "399729605" }, { "host": "x86_64-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", - "size": "399730073" + "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", + "size": "399729605" }, { "host": "arm64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", - "size": "399730073" + "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", + "size": "399729605" }, { "host": "x86_64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", - "size": "399730073" + "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", + "size": "399729605" }, { "host": "x86_64-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", - "size": "399730073" + "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", + "size": "399729605" }, { "host": "i686-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", - "size": "399730073" + "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", + "size": "399729605" }, { "host": "aarch64-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", - "size": "399730073" + "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", + "size": "399729605" }, { "host": "arm-linux-gnueabihf", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:7af392cc8c0079f3eea5e49706f3ea296bd42c4ce89d48909a135310caa69c96", - "size": "399730073" + "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", + "size": "399729605" } ] }, From 5d873c0787fa96675f74b68d16b9b8a3a2a048ea Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Fri, 4 Oct 2024 12:49:55 +0200 Subject: [PATCH 042/406] Add conditional compilation for second I2C interface based on SOC_I2C_NUM (#10408) The ESP32, ESP32-S and ESP32-H series have two I2C interfaces, while the ESP32-C series has only one. --- libraries/Wire/src/Wire.cpp | 2 ++ libraries/Wire/src/Wire.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 047795f949a..8ac0c25595d 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -646,6 +646,8 @@ void TwoWire::onRequestService(uint8_t num, void *arg) { #endif /* SOC_I2C_SUPPORT_SLAVE */ TwoWire Wire = TwoWire(0); +#if SOC_I2C_NUM > 1 TwoWire Wire1 = TwoWire(1); +#endif /* SOC_I2C_NUM */ #endif /* SOC_I2C_SUPPORTED */ diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index fcf94313d52..cf720d48234 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -144,7 +144,9 @@ class TwoWire : public HardwareI2C { }; extern TwoWire Wire; +#if SOC_I2C_NUM > 1 extern TwoWire Wire1; +#endif /* SOC_I2C_NUM */ #endif /* SOC_I2C_SUPPORTED */ #endif /* TwoWire_h */ From 13511a6b6559634ff77550ed0719114183b8d910 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 4 Oct 2024 07:51:47 -0300 Subject: [PATCH 043/406] ci(tests): Add linpack FPU tests (#10389) * ci(tests): Add linpack FPU tests * fix(linpack): Change prints to log_d * fix(linpack): Fix number of runs check * ci(pre-commit): Apply automatic fixes * fix(spelling): Correct spelling mistakes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- tests/performance/linpack_double/ci.json | 6 + .../linpack_double/linpack_double.ino | 1094 +++++++++++++++++ .../linpack_double/test_linpack_double.py | 61 + tests/performance/linpack_float/ci.json | 6 + .../linpack_float/linpack_float.ino | 1094 +++++++++++++++++ .../linpack_float/test_linpack_float.py | 61 + 6 files changed, 2322 insertions(+) create mode 100644 tests/performance/linpack_double/ci.json create mode 100644 tests/performance/linpack_double/linpack_double.ino create mode 100644 tests/performance/linpack_double/test_linpack_double.py create mode 100644 tests/performance/linpack_float/ci.json create mode 100644 tests/performance/linpack_float/linpack_float.ino create mode 100644 tests/performance/linpack_float/test_linpack_float.py diff --git a/tests/performance/linpack_double/ci.json b/tests/performance/linpack_double/ci.json new file mode 100644 index 00000000000..accee2b2135 --- /dev/null +++ b/tests/performance/linpack_double/ci.json @@ -0,0 +1,6 @@ +{ + "platforms": { + "qemu": false, + "wokwi": false + } +} diff --git a/tests/performance/linpack_double/linpack_double.ino b/tests/performance/linpack_double/linpack_double.ino new file mode 100644 index 00000000000..5148b6ef591 --- /dev/null +++ b/tests/performance/linpack_double/linpack_double.ino @@ -0,0 +1,1094 @@ +/* + Linpack test for Arduino and ESP32. + Based on https://github.com/VioletGiraffe/EmbeddedLinpack + Created by Violet Giraffe, 2018 + Adapted by Lucas Saavedra Vaz, 2024 +*/ + +#include +#include + +// Number of runs to average +#define N_RUNS 1000 + +using floating_point_t = double; +bool type_float; + +floating_point_t benchmark(void); +floating_point_t cpu_time(void); +void daxpy(int n, floating_point_t da, floating_point_t dx[], int incx, floating_point_t dy[], int incy); +floating_point_t ddot(int n, floating_point_t dx[], int incx, floating_point_t dy[], int incy); +int dgefa(floating_point_t a[], int lda, int n, int ipvt[]); +void dgesl(floating_point_t a[], int lda, int n, int ipvt[], floating_point_t b[], int job); +void dscal(int n, floating_point_t sa, floating_point_t x[], int incx); +int idamax(int n, floating_point_t dx[], int incx); +floating_point_t r8_abs(floating_point_t x); +floating_point_t r8_epsilon(void); +floating_point_t r8_max(floating_point_t x, floating_point_t y); +floating_point_t r8_random(int iseed[4]); +void r8mat_gen(int lda, int n, floating_point_t *a); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + String data_type; + + if (sizeof(floating_point_t) == sizeof(float)) { + data_type = "float"; + type_float = true; + } else if (sizeof(floating_point_t) == sizeof(double)) { + data_type = "double"; + type_float = false; + } else { + data_type = "unknown"; + log_e("Unknown data type size. Aborting."); + while (1); + } + + log_d("Starting Linpack %s test", data_type.c_str()); + Serial.printf("Runs: %d\n", N_RUNS); + Serial.printf("Type: %s\n", data_type.c_str()); + Serial.flush(); + int i = 0; + + floating_point_t minMflops = 1000000000.0, maxMflops = 0.0, avgMflops = 0.0; + for (i = 0; i < N_RUNS; ++i) { + Serial.printf("Run %d\n", i); + const auto mflops = benchmark(); + avgMflops += mflops; + minMflops = fmin(mflops, minMflops); + maxMflops = fmax(mflops, maxMflops); + Serial.flush(); + } + + avgMflops /= N_RUNS; + Serial.println(String("Runs completed: ") + i); + Serial.println(String("Average MFLOPS: ") + avgMflops); + Serial.println(String("Min MFLOPS: ") + minMflops); + Serial.println(String("Max MFLOPS: ") + maxMflops); + Serial.flush(); +} + +void loop() { + vTaskDelete(NULL); +} + +/******************************************************************************/ + +floating_point_t benchmark(void) + +/******************************************************************************/ +/* + Purpose: + + MAIN is the main program for LINPACK_BENCH. + + Discussion: + + LINPACK_BENCH drives the floating_point_t precision LINPACK benchmark program. + + Modified: + + 25 July 2008 + + Parameters: + + N is the problem size. +*/ +{ +#define N 8 +#define LDA (N + 1) + + static floating_point_t a[N * LDA]; + static floating_point_t a_max; + static floating_point_t b[N]; + static floating_point_t b_max; + const floating_point_t cray = 0.056; + static floating_point_t eps; + int i; + int info; + static int ipvt[N]; + int j; + int job; + floating_point_t ops; + static floating_point_t resid[N]; + floating_point_t resid_max; + [[maybe_unused]] + floating_point_t residn; + static floating_point_t rhs[N]; + floating_point_t t1; + floating_point_t t2; + static floating_point_t time[6]; + floating_point_t total; + floating_point_t x[N]; + + log_d("LINPACK_BENCH"); + log_d(" C version"); + log_d(" The LINPACK benchmark."); + log_d(" Language: C"); + if (!type_float) { + log_d(" Datatype: Double precision real"); + } else if (type_float) { + log_d(" Datatype: Single precision real"); + } else { + log_d(" Datatype: unknown"); + } + log_d(" Matrix order N = %d", N); + log_d(" Leading matrix dimension LDA = %d", LDA); + + ops = (floating_point_t)(2L * N * N * N) / 3.0 + 2.0 * (floating_point_t)((long)N * N); + + /* + Allocate space for arrays. +*/ + r8mat_gen(LDA, N, a); + + a_max = 0.0; + for (j = 0; j < N; j++) { + for (i = 0; i < N; i++) { + a_max = r8_max(a_max, a[i + j * LDA]); + } + } + + for (i = 0; i < N; i++) { + x[i] = 1.0; + } + + for (i = 0; i < N; i++) { + b[i] = 0.0; + for (j = 0; j < N; j++) { + b[i] = b[i] + a[i + j * LDA] * x[j]; + } + } + t1 = cpu_time(); + + info = dgefa(a, LDA, N, ipvt); + + if (info != 0) { + log_d("LINPACK_BENCH - Fatal error!"); + log_d(" The matrix A is apparently singular."); + log_d(" Abnormal end of execution."); + return 1; + } + + t2 = cpu_time(); + time[0] = t2 - t1; + + t1 = cpu_time(); + + job = 0; + dgesl(a, LDA, N, ipvt, b, job); + + t2 = cpu_time(); + time[1] = t2 - t1; + + total = time[0] + time[1]; + + /* + Compute a residual to verify results. +*/ + r8mat_gen(LDA, N, a); + + for (i = 0; i < N; i++) { + x[i] = 1.0; + } + + for (i = 0; i < N; i++) { + rhs[i] = 0.0; + for (j = 0; j < N; j++) { + rhs[i] = rhs[i] + a[i + j * LDA] * x[j]; + } + } + + for (i = 0; i < N; i++) { + resid[i] = -rhs[i]; + for (j = 0; j < N; j++) { + resid[i] = resid[i] + a[i + j * LDA] * b[j]; + } + } + + resid_max = 0.0; + for (i = 0; i < N; i++) { + resid_max = r8_max(resid_max, r8_abs(resid[i])); + } + + b_max = 0.0; + for (i = 0; i < N; i++) { + b_max = r8_max(b_max, r8_abs(b[i])); + } + + eps = r8_epsilon(); + + residn = resid_max / (floating_point_t)N / a_max / b_max / eps; + + time[2] = total; + if (0.0 < total) { + time[3] = ops / (1.0E+06 * total); + } else { + time[3] = -1.0; + } + time[4] = 2.0 / time[3]; + time[5] = total / cray; + + log_d(""); + log_d(" Norm. Resid Resid MACHEP X[1] X[N]"); + log_d(" %14f %14f %14e %14f %14f", residn, resid_max, eps, b[0], b[N - 1]); + log_d(""); + log_d(" Factor Solve Total MFLOPS Unit Cray-Ratio"); + log_d(" %9f %9f %9f %9f %9f %9f", time[0], time[1], time[2], time[3], time[4], time[5]); + + /* + Terminate. +*/ + log_d(""); + log_d("LINPACK_BENCH"); + log_d(" Normal end of execution."); + log_d(""); + + return time[3]; +#undef LDA +#undef N +} +/******************************************************************************/ + +floating_point_t cpu_time(void) + +/******************************************************************************/ +/* + Purpose: + + CPU_TIME returns the current reading on the CPU clock. + + Discussion: + + The CPU time measurements available through this routine are often + not very accurate. In some cases, the accuracy is no better than + a hundredth of a second. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 06 June 2005 + + Author: + + John Burkardt + + Parameters: + + Output, floating_point_t CPU_TIME, the current reading of the CPU clock, in seconds. +*/ +{ + floating_point_t value; + + value = (floating_point_t)micros() / (floating_point_t)1000000; + + return value; +} +/******************************************************************************/ + +void daxpy(int n, floating_point_t da, floating_point_t dx[], int incx, floating_point_t dy[], int incy) + +/******************************************************************************/ +/* + Purpose: + + DAXPY computes constant times a vector plus a vector. + + Discussion: + + This routine uses unrolled loops for increments equal to one. + + Modified: + + 30 March 2007 + + Author: + + FORTRAN77 original by Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart. + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of elements in DX and DY. + + Input, floating_point_t DA, the multiplier of DX. + + Input, floating_point_t DX[*], the first vector. + + Input, int INCX, the increment between successive entries of DX. + + Input/output, floating_point_t DY[*], the second vector. + On output, DY[*] has been replaced by DY[*] + DA * DX[*]. + + Input, int INCY, the increment between successive entries of DY. +*/ +{ + int i; + int ix; + int iy; + int m; + + if (n <= 0) { + return; + } + + if (da == 0.0) { + return; + } + /* + Code for unequal increments or equal increments + not equal to 1. +*/ + if (incx != 1 || incy != 1) { + if (0 <= incx) { + ix = 0; + } else { + ix = (-n + 1) * incx; + } + + if (0 <= incy) { + iy = 0; + } else { + iy = (-n + 1) * incy; + } + + for (i = 0; i < n; i++) { + dy[iy] = dy[iy] + da * dx[ix]; + ix = ix + incx; + iy = iy + incy; + } + } + /* + Code for both increments equal to 1. +*/ + else { + m = n % 4; + + for (i = 0; i < m; i++) { + dy[i] = dy[i] + da * dx[i]; + } + + for (i = m; i < n; i = i + 4) { + dy[i] = dy[i] + da * dx[i]; + dy[i + 1] = dy[i + 1] + da * dx[i + 1]; + dy[i + 2] = dy[i + 2] + da * dx[i + 2]; + dy[i + 3] = dy[i + 3] + da * dx[i + 3]; + } + } + return; +} +/******************************************************************************/ + +floating_point_t ddot(int n, floating_point_t dx[], int incx, floating_point_t dy[], int incy) + +/******************************************************************************/ +/* + Purpose: + + DDOT forms the dot product of two vectors. + + Discussion: + + This routine uses unrolled loops for increments equal to one. + + Modified: + + 30 March 2007 + + Author: + + FORTRAN77 original by Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart. + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vectors. + + Input, floating_point_t DX[*], the first vector. + + Input, int INCX, the increment between successive entries in DX. + + Input, floating_point_t DY[*], the second vector. + + Input, int INCY, the increment between successive entries in DY. + + Output, floating_point_t DDOT, the sum of the product of the corresponding + entries of DX and DY. +*/ +{ + floating_point_t dtemp; + int i; + int ix; + int iy; + int m; + + dtemp = 0.0; + + if (n <= 0) { + return dtemp; + } + /* + Code for unequal increments or equal increments + not equal to 1. +*/ + if (incx != 1 || incy != 1) { + if (0 <= incx) { + ix = 0; + } else { + ix = (-n + 1) * incx; + } + + if (0 <= incy) { + iy = 0; + } else { + iy = (-n + 1) * incy; + } + + for (i = 0; i < n; i++) { + dtemp = dtemp + dx[ix] * dy[iy]; + ix = ix + incx; + iy = iy + incy; + } + } + /* + Code for both increments equal to 1. +*/ + else { + m = n % 5; + + for (i = 0; i < m; i++) { + dtemp = dtemp + dx[i] * dy[i]; + } + + for (i = m; i < n; i = i + 5) { + dtemp = dtemp + dx[i] * dy[i] + dx[i + 1] * dy[i + 1] + dx[i + 2] * dy[i + 2] + dx[i + 3] * dy[i + 3] + dx[i + 4] * dy[i + 4]; + } + } + return dtemp; +} +/******************************************************************************/ + +int dgefa(floating_point_t a[], int lda, int n, int ipvt[]) + +/******************************************************************************/ +/* + Purpose: + + DGEFA factors a real general matrix. + + Modified: + + 16 May 2005 + + Author: + + C version by John Burkardt. + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, + LINPACK User's Guide, + SIAM, (Society for Industrial and Applied Mathematics), + 3600 University City Science Center, + Philadelphia, PA, 19104-2688. + ISBN 0-89871-172-X + + Parameters: + + Input/output, floating_point_t A[LDA*N]. + On input, the matrix to be factored. + On output, an upper triangular matrix and the multipliers used to obtain + it. The factorization can be written A=L*U, where L is a product of + permutation and unit lower triangular matrices, and U is upper triangular. + + Input, int LDA, the leading dimension of A. + + Input, int N, the order of the matrix A. + + Output, int IPVT[N], the pivot indices. + + Output, int DGEFA, singularity indicator. + 0, normal value. + K, if U(K,K) == 0. This is not an error condition for this subroutine, + but it does indicate that DGESL or DGEDI will divide by zero if called. + Use RCOND in DGECO for a reliable indication of singularity. +*/ +{ + int info; + int j; + int k; + int l; + floating_point_t t; + /* + Gaussian elimination with partial pivoting. +*/ + info = 0; + + for (k = 1; k <= n - 1; k++) { + /* + Find L = pivot index. +*/ + l = idamax(n - k + 1, a + (k - 1) + (k - 1) * lda, 1) + k - 1; + ipvt[k - 1] = l; + /* + Zero pivot implies this column already triangularized. +*/ + if (a[l - 1 + (k - 1) * lda] == 0.0) { + info = k; + continue; + } + /* + Interchange if necessary. +*/ + if (l != k) { + t = a[l - 1 + (k - 1) * lda]; + a[l - 1 + (k - 1) * lda] = a[k - 1 + (k - 1) * lda]; + a[k - 1 + (k - 1) * lda] = t; + } + /* + Compute multipliers. +*/ + t = -1.0 / a[k - 1 + (k - 1) * lda]; + + dscal(n - k, t, a + k + (k - 1) * lda, 1); + /* + Row elimination with column indexing. +*/ + for (j = k + 1; j <= n; j++) { + t = a[l - 1 + (j - 1) * lda]; + if (l != k) { + a[l - 1 + (j - 1) * lda] = a[k - 1 + (j - 1) * lda]; + a[k - 1 + (j - 1) * lda] = t; + } + daxpy(n - k, t, a + k + (k - 1) * lda, 1, a + k + (j - 1) * lda, 1); + } + } + + ipvt[n - 1] = n; + + if (a[n - 1 + (n - 1) * lda] == 0.0) { + info = n; + } + + return info; +} +/******************************************************************************/ + +void dgesl(floating_point_t a[], int lda, int n, int ipvt[], floating_point_t b[], int job) + +/******************************************************************************/ +/* + Purpose: + + DGESL solves a real general linear system A * X = B. + + Discussion: + + DGESL can solve either of the systems A * X = B or A' * X = B. + + The system matrix must have been factored by DGECO or DGEFA. + + A division by zero will occur if the input factor contains a + zero on the diagonal. Technically this indicates singularity + but it is often caused by improper arguments or improper + setting of LDA. It will not occur if the subroutines are + called correctly and if DGECO has set 0.0 < RCOND + or DGEFA has set INFO == 0. + + Modified: + + 16 May 2005 + + Author: + + C version by John Burkardt. + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, + LINPACK User's Guide, + SIAM, (Society for Industrial and Applied Mathematics), + 3600 University City Science Center, + Philadelphia, PA, 19104-2688. + ISBN 0-89871-172-X + + Parameters: + + Input, floating_point_t A[LDA*N], the output from DGECO or DGEFA. + + Input, int LDA, the leading dimension of A. + + Input, int N, the order of the matrix A. + + Input, int IPVT[N], the pivot vector from DGECO or DGEFA. + + Input/output, floating_point_t B[N]. + On input, the right hand side vector. + On output, the solution vector. + + Input, int JOB. + 0, solve A * X = B; + nonzero, solve A' * X = B. +*/ +{ + int k; + int l; + floating_point_t t; + /* + Solve A * X = B. +*/ + if (job == 0) { + for (k = 1; k <= n - 1; k++) { + l = ipvt[k - 1]; + t = b[l - 1]; + + if (l != k) { + b[l - 1] = b[k - 1]; + b[k - 1] = t; + } + + daxpy(n - k, t, a + k + (k - 1) * lda, 1, b + k, 1); + } + + for (k = n; 1 <= k; k--) { + b[k - 1] = b[k - 1] / a[k - 1 + (k - 1) * lda]; + t = -b[k - 1]; + daxpy(k - 1, t, a + 0 + (k - 1) * lda, 1, b, 1); + } + } + /* + Solve A' * X = B. +*/ + else { + for (k = 1; k <= n; k++) { + t = ddot(k - 1, a + 0 + (k - 1) * lda, 1, b, 1); + b[k - 1] = (b[k - 1] - t) / a[k - 1 + (k - 1) * lda]; + } + + for (k = n - 1; 1 <= k; k--) { + b[k - 1] = b[k - 1] + ddot(n - k, a + k + (k - 1) * lda, 1, b + k, 1); + l = ipvt[k - 1]; + + if (l != k) { + t = b[l - 1]; + b[l - 1] = b[k - 1]; + b[k - 1] = t; + } + } + } + return; +} +/******************************************************************************/ + +void dscal(int n, floating_point_t sa, floating_point_t x[], int incx) + +/******************************************************************************/ +/* + Purpose: + + DSCAL scales a vector by a constant. + + Modified: + + 30 March 2007 + + Author: + + FORTRAN77 original by Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart. + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vector. + + Input, floating_point_t SA, the multiplier. + + Input/output, floating_point_t X[*], the vector to be scaled. + + Input, int INCX, the increment between successive entries of X. +*/ +{ + int i; + int ix; + int m; + + if (n <= 0) { + } else if (incx == 1) { + m = n % 5; + + for (i = 0; i < m; i++) { + x[i] = sa * x[i]; + } + + for (i = m; i < n; i = i + 5) { + x[i] = sa * x[i]; + x[i + 1] = sa * x[i + 1]; + x[i + 2] = sa * x[i + 2]; + x[i + 3] = sa * x[i + 3]; + x[i + 4] = sa * x[i + 4]; + } + } else { + if (0 <= incx) { + ix = 0; + } else { + ix = (-n + 1) * incx; + } + + for (i = 0; i < n; i++) { + x[ix] = sa * x[ix]; + ix = ix + incx; + } + } + return; +} +/******************************************************************************/ + +int idamax(int n, floating_point_t dx[], int incx) + +/******************************************************************************/ +/* + Purpose: + + IDAMAX finds the index of the vector element of maximum absolute value. + + Discussion: + + WARNING: This index is a 1-based index, not a 0-based index! + + Modified: + + 30 March 2007 + + Author: + + FORTRAN77 original by Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart. + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vector. + + Input, floating_point_t X[*], the vector to be examined. + + Input, int INCX, the increment between successive entries of SX. + + Output, int IDAMAX, the index of the element of maximum + absolute value. +*/ +{ + floating_point_t dmax; + int i; + int ix; + int value; + + value = 0; + + if (n < 1 || incx <= 0) { + return value; + } + + value = 1; + + if (n == 1) { + return value; + } + + if (incx == 1) { + dmax = r8_abs(dx[0]); + + for (i = 1; i < n; i++) { + if (dmax < r8_abs(dx[i])) { + value = i + 1; + dmax = r8_abs(dx[i]); + } + } + } else { + ix = 0; + dmax = r8_abs(dx[0]); + ix = ix + incx; + + for (i = 1; i < n; i++) { + if (dmax < r8_abs(dx[ix])) { + value = i + 1; + dmax = r8_abs(dx[ix]); + } + ix = ix + incx; + } + } + + return value; +} +/******************************************************************************/ + +floating_point_t r8_abs(floating_point_t x) + +/******************************************************************************/ +/* + Purpose: + + R8_ABS returns the absolute value of a R8. + + Modified: + + 02 April 2005 + + Author: + + John Burkardt + + Parameters: + + Input, floating_point_t X, the quantity whose absolute value is desired. + + Output, floating_point_t R8_ABS, the absolute value of X. +*/ +{ + floating_point_t value; + + if (0.0 <= x) { + value = x; + } else { + value = -x; + } + return value; +} +/******************************************************************************/ + +floating_point_t r8_epsilon(void) + +/******************************************************************************/ +/* + Purpose: + + R8_EPSILON returns the R8 round off unit. + + Discussion: + + R8_EPSILON is a number R which is a power of 2 with the property that, + to the precision of the computer's arithmetic, + 1 < 1 + R + but + 1 = ( 1 + R / 2 ) + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 08 May 2006 + + Author: + + John Burkardt + + Parameters: + + Output, floating_point_t R8_EPSILON, the floating_point_t precision round-off unit. +*/ +{ + floating_point_t r; + + r = 1.0; + + while (1.0 < (floating_point_t)(1.0 + r)) { + r = r / 2.0; + } + r = 2.0 * r; + + return r; +} +/******************************************************************************/ + +floating_point_t r8_max(floating_point_t x, floating_point_t y) + +/******************************************************************************/ +/* + Purpose: + + R8_MAX returns the maximum of two R8's. + + Modified: + + 18 August 2004 + + Author: + + John Burkardt + + Parameters: + + Input, floating_point_t X, Y, the quantities to compare. + + Output, floating_point_t R8_MAX, the maximum of X and Y. +*/ +{ + floating_point_t value; + + if (y < x) { + value = x; + } else { + value = y; + } + return value; +} +/******************************************************************************/ + +floating_point_t r8_random(int iseed[4]) + +/******************************************************************************/ +/* + Purpose: + + R8_RANDOM returns a uniformly distributed random number between 0 and 1. + + Discussion: + + This routine uses a multiplicative congruential method with modulus + 2**48 and multiplier 33952834046453 (see G.S.Fishman, + 'Multiplicative congruential random number generators with modulus + 2**b: an exhaustive analysis for b = 32 and a partial analysis for + b = 48', Math. Comp. 189, pp 331-344, 1990). + + 48-bit integers are stored in 4 integer array elements with 12 bits + per element. Hence the routine is portable across machines with + integers of 32 bits or more. + + Parameters: + + Input/output, integer ISEED(4). + On entry, the seed of the random number generator; the array + elements must be between 0 and 4095, and ISEED(4) must be odd. + On exit, the seed is updated. + + Output, floating_point_t R8_RANDOM, the next pseudorandom number. +*/ +{ + int ipw2 = 4096; + int it1; + int it2; + int it3; + int it4; + int m1 = 494; + int m2 = 322; + int m3 = 2508; + int m4 = 2549; + floating_point_t r = 1.0 / 4096.0; + floating_point_t value; + /* + Multiply the seed by the multiplier modulo 2**48. +*/ + it4 = iseed[3] * m4; + it3 = it4 / ipw2; + it4 = it4 - ipw2 * it3; + it3 = it3 + iseed[2] * m4 + iseed[3] * m3; + it2 = it3 / ipw2; + it3 = it3 - ipw2 * it2; + it2 = it2 + iseed[1] * m4 + iseed[2] * m3 + iseed[3] * m2; + it1 = it2 / ipw2; + it2 = it2 - ipw2 * it1; + it1 = it1 + iseed[0] * m4 + iseed[1] * m3 + iseed[2] * m2 + iseed[3] * m1; + it1 = (it1 % ipw2); + /* + Return updated seed +*/ + iseed[0] = it1; + iseed[1] = it2; + iseed[2] = it3; + iseed[3] = it4; + /* + Convert 48-bit integer to a real number in the interval (0,1) +*/ + value = r * ((floating_point_t)(it1) + r * ((floating_point_t)(it2) + r * ((floating_point_t)(it3) + r * ((floating_point_t)(it4))))); + + return value; +} +/******************************************************************************/ + +void r8mat_gen(int lda, int n, floating_point_t *a) + +/******************************************************************************/ +/* + Purpose: + + R8MAT_GEN generates a random R8MAT. + + Modified: + + 06 June 2005 + + Parameters: + + Input, integer LDA, the leading dimension of the matrix. + + Input, integer N, the order of the matrix. + + Output, floating_point_t R8MAT_GEN[LDA*N], the N by N matrix. +*/ +{ + int i; + int init[4] = {1, 2, 3, 1325}; + int j; + + for (j = 1; j <= n; j++) { + for (i = 1; i <= n; i++) { + a[i - 1 + (j - 1) * lda] = r8_random(init) - 0.5; + } + } +} +/******************************************************************************/ diff --git a/tests/performance/linpack_double/test_linpack_double.py b/tests/performance/linpack_double/test_linpack_double.py new file mode 100644 index 00000000000..0a6e2f90ef3 --- /dev/null +++ b/tests/performance/linpack_double/test_linpack_double.py @@ -0,0 +1,61 @@ +import json +import logging +import os + + +def test_linpack_double(dut, request): + LOGGER = logging.getLogger(__name__) + + # Match "Runs: %d" + res = dut.expect(r"Runs: (\d+)", timeout=60) + runs = int(res.group(0).decode("utf-8").split(" ")[1]) + LOGGER.info("Number of runs: {}".format(runs)) + assert runs > 0, "Invalid number of runs" + + # Match "Type: %s" + res = dut.expect(r"Type: (\w+)", timeout=60) + data_type = res.group(0).decode("utf-8").split(" ")[1] + LOGGER.info("Data type: {}".format(data_type)) + assert data_type == "double", "Invalid data type" + + # Match "Runs completed: %d" + res = dut.expect(r"Runs completed: (\d+)", timeout=120) + runs_completed = int(res.group(0).decode("utf-8").split(" ")[2]) + LOGGER.info("Runs completed: {}".format(runs_completed)) + assert runs_completed == runs, "Invalid number of runs completed" + + # Match "Average MFLOPS: %f" + res = dut.expect(r"Average MFLOPS: (\d+\.\d+)", timeout=120) + avg_score = float(res.group(0).decode("utf-8").split(" ")[2]) + LOGGER.info("Average MFLOPS: {}".format(avg_score)) + assert avg_score > 0, "Invalid average MFLOPS" + + # Match "Min MFLOPS: %f" + res = dut.expect(r"Min MFLOPS: (\d+\.\d+)", timeout=120) + min_score = float(res.group(0).decode("utf-8").split(" ")[2]) + LOGGER.info("Min MFLOPS: {}".format(min_score)) + assert min_score > 0 and min_score < 1000000000.0, "Invalid min MFLOPS" + + # Match "Max MFLOPS: %f" + res = dut.expect(r"Max MFLOPS: (\d+\.\d+)", timeout=120) + max_score = float(res.group(0).decode("utf-8").split(" ")[2]) + LOGGER.info("Max MFLOPS: {}".format(max_score)) + assert max_score > 0, "Invalid max MFLOPS" + + # Create JSON with results and write it to file + # Always create a JSON with this format (so it can be merged later on): + # { TEST_NAME_STR: TEST_RESULTS_DICT } + results = {"linpack_double": {"runs": runs, "avg_score": avg_score, "min_score": min_score, "max_score": max_score}} + + current_folder = os.path.dirname(request.path) + file_index = 0 + report_file = os.path.join(current_folder, "result_linpack_double" + str(file_index) + ".json") + while os.path.exists(report_file): + report_file = report_file.replace(str(file_index) + ".json", str(file_index + 1) + ".json") + file_index += 1 + + with open(report_file, "w") as f: + try: + f.write(json.dumps(results)) + except Exception as e: + LOGGER.warning("Failed to write results to file: {}".format(e)) diff --git a/tests/performance/linpack_float/ci.json b/tests/performance/linpack_float/ci.json new file mode 100644 index 00000000000..accee2b2135 --- /dev/null +++ b/tests/performance/linpack_float/ci.json @@ -0,0 +1,6 @@ +{ + "platforms": { + "qemu": false, + "wokwi": false + } +} diff --git a/tests/performance/linpack_float/linpack_float.ino b/tests/performance/linpack_float/linpack_float.ino new file mode 100644 index 00000000000..24dd9e7c461 --- /dev/null +++ b/tests/performance/linpack_float/linpack_float.ino @@ -0,0 +1,1094 @@ +/* + Linpack test for Arduino and ESP32. + Based on https://github.com/VioletGiraffe/EmbeddedLinpack + Created by Violet Giraffe, 2018 + Adapted by Lucas Saavedra Vaz, 2024 +*/ + +#include +#include + +// Number of runs to average +#define N_RUNS 1000 + +using floating_point_t = float; +bool type_float; + +floating_point_t benchmark(void); +floating_point_t cpu_time(void); +void daxpy(int n, floating_point_t da, floating_point_t dx[], int incx, floating_point_t dy[], int incy); +floating_point_t ddot(int n, floating_point_t dx[], int incx, floating_point_t dy[], int incy); +int dgefa(floating_point_t a[], int lda, int n, int ipvt[]); +void dgesl(floating_point_t a[], int lda, int n, int ipvt[], floating_point_t b[], int job); +void dscal(int n, floating_point_t sa, floating_point_t x[], int incx); +int idamax(int n, floating_point_t dx[], int incx); +floating_point_t r8_abs(floating_point_t x); +floating_point_t r8_epsilon(void); +floating_point_t r8_max(floating_point_t x, floating_point_t y); +floating_point_t r8_random(int iseed[4]); +void r8mat_gen(int lda, int n, floating_point_t *a); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + String data_type; + + if (sizeof(floating_point_t) == sizeof(float)) { + data_type = "float"; + type_float = true; + } else if (sizeof(floating_point_t) == sizeof(double)) { + data_type = "double"; + type_float = false; + } else { + data_type = "unknown"; + log_e("Unknown data type size. Aborting."); + while (1); + } + + log_d("Starting Linpack %s test", data_type.c_str()); + Serial.printf("Runs: %d\n", N_RUNS); + Serial.printf("Type: %s\n", data_type.c_str()); + Serial.flush(); + int i = 0; + + floating_point_t minMflops = 1000000000.0, maxMflops = 0.0, avgMflops = 0.0; + for (i = 0; i < N_RUNS; ++i) { + Serial.printf("Run %d\n", i); + const auto mflops = benchmark(); + avgMflops += mflops; + minMflops = fmin(mflops, minMflops); + maxMflops = fmax(mflops, maxMflops); + Serial.flush(); + } + + avgMflops /= N_RUNS; + Serial.println(String("Runs completed: ") + i); + Serial.println(String("Average MFLOPS: ") + avgMflops); + Serial.println(String("Min MFLOPS: ") + minMflops); + Serial.println(String("Max MFLOPS: ") + maxMflops); + Serial.flush(); +} + +void loop() { + vTaskDelete(NULL); +} + +/******************************************************************************/ + +floating_point_t benchmark(void) + +/******************************************************************************/ +/* + Purpose: + + MAIN is the main program for LINPACK_BENCH. + + Discussion: + + LINPACK_BENCH drives the floating_point_t precision LINPACK benchmark program. + + Modified: + + 25 July 2008 + + Parameters: + + N is the problem size. +*/ +{ +#define N 8 +#define LDA (N + 1) + + static floating_point_t a[N * LDA]; + static floating_point_t a_max; + static floating_point_t b[N]; + static floating_point_t b_max; + const floating_point_t cray = 0.056; + static floating_point_t eps; + int i; + int info; + static int ipvt[N]; + int j; + int job; + floating_point_t ops; + static floating_point_t resid[N]; + floating_point_t resid_max; + [[maybe_unused]] + floating_point_t residn; + static floating_point_t rhs[N]; + floating_point_t t1; + floating_point_t t2; + static floating_point_t time[6]; + floating_point_t total; + floating_point_t x[N]; + + log_d("LINPACK_BENCH"); + log_d(" C version"); + log_d(" The LINPACK benchmark."); + log_d(" Language: C"); + if (!type_float) { + log_d(" Datatype: Double precision real"); + } else if (type_float) { + log_d(" Datatype: Single precision real"); + } else { + log_d(" Datatype: unknown"); + } + log_d(" Matrix order N = %d", N); + log_d(" Leading matrix dimension LDA = %d", LDA); + + ops = (floating_point_t)(2L * N * N * N) / 3.0 + 2.0 * (floating_point_t)((long)N * N); + + /* + Allocate space for arrays. +*/ + r8mat_gen(LDA, N, a); + + a_max = 0.0; + for (j = 0; j < N; j++) { + for (i = 0; i < N; i++) { + a_max = r8_max(a_max, a[i + j * LDA]); + } + } + + for (i = 0; i < N; i++) { + x[i] = 1.0; + } + + for (i = 0; i < N; i++) { + b[i] = 0.0; + for (j = 0; j < N; j++) { + b[i] = b[i] + a[i + j * LDA] * x[j]; + } + } + t1 = cpu_time(); + + info = dgefa(a, LDA, N, ipvt); + + if (info != 0) { + log_d("LINPACK_BENCH - Fatal error!"); + log_d(" The matrix A is apparently singular."); + log_d(" Abnormal end of execution."); + return 1; + } + + t2 = cpu_time(); + time[0] = t2 - t1; + + t1 = cpu_time(); + + job = 0; + dgesl(a, LDA, N, ipvt, b, job); + + t2 = cpu_time(); + time[1] = t2 - t1; + + total = time[0] + time[1]; + + /* + Compute a residual to verify results. +*/ + r8mat_gen(LDA, N, a); + + for (i = 0; i < N; i++) { + x[i] = 1.0; + } + + for (i = 0; i < N; i++) { + rhs[i] = 0.0; + for (j = 0; j < N; j++) { + rhs[i] = rhs[i] + a[i + j * LDA] * x[j]; + } + } + + for (i = 0; i < N; i++) { + resid[i] = -rhs[i]; + for (j = 0; j < N; j++) { + resid[i] = resid[i] + a[i + j * LDA] * b[j]; + } + } + + resid_max = 0.0; + for (i = 0; i < N; i++) { + resid_max = r8_max(resid_max, r8_abs(resid[i])); + } + + b_max = 0.0; + for (i = 0; i < N; i++) { + b_max = r8_max(b_max, r8_abs(b[i])); + } + + eps = r8_epsilon(); + + residn = resid_max / (floating_point_t)N / a_max / b_max / eps; + + time[2] = total; + if (0.0 < total) { + time[3] = ops / (1.0E+06 * total); + } else { + time[3] = -1.0; + } + time[4] = 2.0 / time[3]; + time[5] = total / cray; + + log_d(""); + log_d(" Norm. Resid Resid MACHEP X[1] X[N]"); + log_d(" %14f %14f %14e %14f %14f", residn, resid_max, eps, b[0], b[N - 1]); + log_d(""); + log_d(" Factor Solve Total MFLOPS Unit Cray-Ratio"); + log_d(" %9f %9f %9f %9f %9f %9f", time[0], time[1], time[2], time[3], time[4], time[5]); + + /* + Terminate. +*/ + log_d(""); + log_d("LINPACK_BENCH"); + log_d(" Normal end of execution."); + log_d(""); + + return time[3]; +#undef LDA +#undef N +} +/******************************************************************************/ + +floating_point_t cpu_time(void) + +/******************************************************************************/ +/* + Purpose: + + CPU_TIME returns the current reading on the CPU clock. + + Discussion: + + The CPU time measurements available through this routine are often + not very accurate. In some cases, the accuracy is no better than + a hundredth of a second. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 06 June 2005 + + Author: + + John Burkardt + + Parameters: + + Output, floating_point_t CPU_TIME, the current reading of the CPU clock, in seconds. +*/ +{ + floating_point_t value; + + value = (floating_point_t)micros() / (floating_point_t)1000000; + + return value; +} +/******************************************************************************/ + +void daxpy(int n, floating_point_t da, floating_point_t dx[], int incx, floating_point_t dy[], int incy) + +/******************************************************************************/ +/* + Purpose: + + DAXPY computes constant times a vector plus a vector. + + Discussion: + + This routine uses unrolled loops for increments equal to one. + + Modified: + + 30 March 2007 + + Author: + + FORTRAN77 original by Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart. + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of elements in DX and DY. + + Input, floating_point_t DA, the multiplier of DX. + + Input, floating_point_t DX[*], the first vector. + + Input, int INCX, the increment between successive entries of DX. + + Input/output, floating_point_t DY[*], the second vector. + On output, DY[*] has been replaced by DY[*] + DA * DX[*]. + + Input, int INCY, the increment between successive entries of DY. +*/ +{ + int i; + int ix; + int iy; + int m; + + if (n <= 0) { + return; + } + + if (da == 0.0) { + return; + } + /* + Code for unequal increments or equal increments + not equal to 1. +*/ + if (incx != 1 || incy != 1) { + if (0 <= incx) { + ix = 0; + } else { + ix = (-n + 1) * incx; + } + + if (0 <= incy) { + iy = 0; + } else { + iy = (-n + 1) * incy; + } + + for (i = 0; i < n; i++) { + dy[iy] = dy[iy] + da * dx[ix]; + ix = ix + incx; + iy = iy + incy; + } + } + /* + Code for both increments equal to 1. +*/ + else { + m = n % 4; + + for (i = 0; i < m; i++) { + dy[i] = dy[i] + da * dx[i]; + } + + for (i = m; i < n; i = i + 4) { + dy[i] = dy[i] + da * dx[i]; + dy[i + 1] = dy[i + 1] + da * dx[i + 1]; + dy[i + 2] = dy[i + 2] + da * dx[i + 2]; + dy[i + 3] = dy[i + 3] + da * dx[i + 3]; + } + } + return; +} +/******************************************************************************/ + +floating_point_t ddot(int n, floating_point_t dx[], int incx, floating_point_t dy[], int incy) + +/******************************************************************************/ +/* + Purpose: + + DDOT forms the dot product of two vectors. + + Discussion: + + This routine uses unrolled loops for increments equal to one. + + Modified: + + 30 March 2007 + + Author: + + FORTRAN77 original by Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart. + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vectors. + + Input, floating_point_t DX[*], the first vector. + + Input, int INCX, the increment between successive entries in DX. + + Input, floating_point_t DY[*], the second vector. + + Input, int INCY, the increment between successive entries in DY. + + Output, floating_point_t DDOT, the sum of the product of the corresponding + entries of DX and DY. +*/ +{ + floating_point_t dtemp; + int i; + int ix; + int iy; + int m; + + dtemp = 0.0; + + if (n <= 0) { + return dtemp; + } + /* + Code for unequal increments or equal increments + not equal to 1. +*/ + if (incx != 1 || incy != 1) { + if (0 <= incx) { + ix = 0; + } else { + ix = (-n + 1) * incx; + } + + if (0 <= incy) { + iy = 0; + } else { + iy = (-n + 1) * incy; + } + + for (i = 0; i < n; i++) { + dtemp = dtemp + dx[ix] * dy[iy]; + ix = ix + incx; + iy = iy + incy; + } + } + /* + Code for both increments equal to 1. +*/ + else { + m = n % 5; + + for (i = 0; i < m; i++) { + dtemp = dtemp + dx[i] * dy[i]; + } + + for (i = m; i < n; i = i + 5) { + dtemp = dtemp + dx[i] * dy[i] + dx[i + 1] * dy[i + 1] + dx[i + 2] * dy[i + 2] + dx[i + 3] * dy[i + 3] + dx[i + 4] * dy[i + 4]; + } + } + return dtemp; +} +/******************************************************************************/ + +int dgefa(floating_point_t a[], int lda, int n, int ipvt[]) + +/******************************************************************************/ +/* + Purpose: + + DGEFA factors a real general matrix. + + Modified: + + 16 May 2005 + + Author: + + C version by John Burkardt. + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, + LINPACK User's Guide, + SIAM, (Society for Industrial and Applied Mathematics), + 3600 University City Science Center, + Philadelphia, PA, 19104-2688. + ISBN 0-89871-172-X + + Parameters: + + Input/output, floating_point_t A[LDA*N]. + On input, the matrix to be factored. + On output, an upper triangular matrix and the multipliers used to obtain + it. The factorization can be written A=L*U, where L is a product of + permutation and unit lower triangular matrices, and U is upper triangular. + + Input, int LDA, the leading dimension of A. + + Input, int N, the order of the matrix A. + + Output, int IPVT[N], the pivot indices. + + Output, int DGEFA, singularity indicator. + 0, normal value. + K, if U(K,K) == 0. This is not an error condition for this subroutine, + but it does indicate that DGESL or DGEDI will divide by zero if called. + Use RCOND in DGECO for a reliable indication of singularity. +*/ +{ + int info; + int j; + int k; + int l; + floating_point_t t; + /* + Gaussian elimination with partial pivoting. +*/ + info = 0; + + for (k = 1; k <= n - 1; k++) { + /* + Find L = pivot index. +*/ + l = idamax(n - k + 1, a + (k - 1) + (k - 1) * lda, 1) + k - 1; + ipvt[k - 1] = l; + /* + Zero pivot implies this column already triangularized. +*/ + if (a[l - 1 + (k - 1) * lda] == 0.0) { + info = k; + continue; + } + /* + Interchange if necessary. +*/ + if (l != k) { + t = a[l - 1 + (k - 1) * lda]; + a[l - 1 + (k - 1) * lda] = a[k - 1 + (k - 1) * lda]; + a[k - 1 + (k - 1) * lda] = t; + } + /* + Compute multipliers. +*/ + t = -1.0 / a[k - 1 + (k - 1) * lda]; + + dscal(n - k, t, a + k + (k - 1) * lda, 1); + /* + Row elimination with column indexing. +*/ + for (j = k + 1; j <= n; j++) { + t = a[l - 1 + (j - 1) * lda]; + if (l != k) { + a[l - 1 + (j - 1) * lda] = a[k - 1 + (j - 1) * lda]; + a[k - 1 + (j - 1) * lda] = t; + } + daxpy(n - k, t, a + k + (k - 1) * lda, 1, a + k + (j - 1) * lda, 1); + } + } + + ipvt[n - 1] = n; + + if (a[n - 1 + (n - 1) * lda] == 0.0) { + info = n; + } + + return info; +} +/******************************************************************************/ + +void dgesl(floating_point_t a[], int lda, int n, int ipvt[], floating_point_t b[], int job) + +/******************************************************************************/ +/* + Purpose: + + DGESL solves a real general linear system A * X = B. + + Discussion: + + DGESL can solve either of the systems A * X = B or A' * X = B. + + The system matrix must have been factored by DGECO or DGEFA. + + A division by zero will occur if the input factor contains a + zero on the diagonal. Technically this indicates singularity + but it is often caused by improper arguments or improper + setting of LDA. It will not occur if the subroutines are + called correctly and if DGECO has set 0.0 < RCOND + or DGEFA has set INFO == 0. + + Modified: + + 16 May 2005 + + Author: + + C version by John Burkardt. + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, + LINPACK User's Guide, + SIAM, (Society for Industrial and Applied Mathematics), + 3600 University City Science Center, + Philadelphia, PA, 19104-2688. + ISBN 0-89871-172-X + + Parameters: + + Input, floating_point_t A[LDA*N], the output from DGECO or DGEFA. + + Input, int LDA, the leading dimension of A. + + Input, int N, the order of the matrix A. + + Input, int IPVT[N], the pivot vector from DGECO or DGEFA. + + Input/output, floating_point_t B[N]. + On input, the right hand side vector. + On output, the solution vector. + + Input, int JOB. + 0, solve A * X = B; + nonzero, solve A' * X = B. +*/ +{ + int k; + int l; + floating_point_t t; + /* + Solve A * X = B. +*/ + if (job == 0) { + for (k = 1; k <= n - 1; k++) { + l = ipvt[k - 1]; + t = b[l - 1]; + + if (l != k) { + b[l - 1] = b[k - 1]; + b[k - 1] = t; + } + + daxpy(n - k, t, a + k + (k - 1) * lda, 1, b + k, 1); + } + + for (k = n; 1 <= k; k--) { + b[k - 1] = b[k - 1] / a[k - 1 + (k - 1) * lda]; + t = -b[k - 1]; + daxpy(k - 1, t, a + 0 + (k - 1) * lda, 1, b, 1); + } + } + /* + Solve A' * X = B. +*/ + else { + for (k = 1; k <= n; k++) { + t = ddot(k - 1, a + 0 + (k - 1) * lda, 1, b, 1); + b[k - 1] = (b[k - 1] - t) / a[k - 1 + (k - 1) * lda]; + } + + for (k = n - 1; 1 <= k; k--) { + b[k - 1] = b[k - 1] + ddot(n - k, a + k + (k - 1) * lda, 1, b + k, 1); + l = ipvt[k - 1]; + + if (l != k) { + t = b[l - 1]; + b[l - 1] = b[k - 1]; + b[k - 1] = t; + } + } + } + return; +} +/******************************************************************************/ + +void dscal(int n, floating_point_t sa, floating_point_t x[], int incx) + +/******************************************************************************/ +/* + Purpose: + + DSCAL scales a vector by a constant. + + Modified: + + 30 March 2007 + + Author: + + FORTRAN77 original by Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart. + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vector. + + Input, floating_point_t SA, the multiplier. + + Input/output, floating_point_t X[*], the vector to be scaled. + + Input, int INCX, the increment between successive entries of X. +*/ +{ + int i; + int ix; + int m; + + if (n <= 0) { + } else if (incx == 1) { + m = n % 5; + + for (i = 0; i < m; i++) { + x[i] = sa * x[i]; + } + + for (i = m; i < n; i = i + 5) { + x[i] = sa * x[i]; + x[i + 1] = sa * x[i + 1]; + x[i + 2] = sa * x[i + 2]; + x[i + 3] = sa * x[i + 3]; + x[i + 4] = sa * x[i + 4]; + } + } else { + if (0 <= incx) { + ix = 0; + } else { + ix = (-n + 1) * incx; + } + + for (i = 0; i < n; i++) { + x[ix] = sa * x[ix]; + ix = ix + incx; + } + } + return; +} +/******************************************************************************/ + +int idamax(int n, floating_point_t dx[], int incx) + +/******************************************************************************/ +/* + Purpose: + + IDAMAX finds the index of the vector element of maximum absolute value. + + Discussion: + + WARNING: This index is a 1-based index, not a 0-based index! + + Modified: + + 30 March 2007 + + Author: + + FORTRAN77 original by Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart. + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vector. + + Input, floating_point_t X[*], the vector to be examined. + + Input, int INCX, the increment between successive entries of SX. + + Output, int IDAMAX, the index of the element of maximum + absolute value. +*/ +{ + floating_point_t dmax; + int i; + int ix; + int value; + + value = 0; + + if (n < 1 || incx <= 0) { + return value; + } + + value = 1; + + if (n == 1) { + return value; + } + + if (incx == 1) { + dmax = r8_abs(dx[0]); + + for (i = 1; i < n; i++) { + if (dmax < r8_abs(dx[i])) { + value = i + 1; + dmax = r8_abs(dx[i]); + } + } + } else { + ix = 0; + dmax = r8_abs(dx[0]); + ix = ix + incx; + + for (i = 1; i < n; i++) { + if (dmax < r8_abs(dx[ix])) { + value = i + 1; + dmax = r8_abs(dx[ix]); + } + ix = ix + incx; + } + } + + return value; +} +/******************************************************************************/ + +floating_point_t r8_abs(floating_point_t x) + +/******************************************************************************/ +/* + Purpose: + + R8_ABS returns the absolute value of a R8. + + Modified: + + 02 April 2005 + + Author: + + John Burkardt + + Parameters: + + Input, floating_point_t X, the quantity whose absolute value is desired. + + Output, floating_point_t R8_ABS, the absolute value of X. +*/ +{ + floating_point_t value; + + if (0.0 <= x) { + value = x; + } else { + value = -x; + } + return value; +} +/******************************************************************************/ + +floating_point_t r8_epsilon(void) + +/******************************************************************************/ +/* + Purpose: + + R8_EPSILON returns the R8 round off unit. + + Discussion: + + R8_EPSILON is a number R which is a power of 2 with the property that, + to the precision of the computer's arithmetic, + 1 < 1 + R + but + 1 = ( 1 + R / 2 ) + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 08 May 2006 + + Author: + + John Burkardt + + Parameters: + + Output, floating_point_t R8_EPSILON, the floating_point_t precision round-off unit. +*/ +{ + floating_point_t r; + + r = 1.0; + + while (1.0 < (floating_point_t)(1.0 + r)) { + r = r / 2.0; + } + r = 2.0 * r; + + return r; +} +/******************************************************************************/ + +floating_point_t r8_max(floating_point_t x, floating_point_t y) + +/******************************************************************************/ +/* + Purpose: + + R8_MAX returns the maximum of two R8's. + + Modified: + + 18 August 2004 + + Author: + + John Burkardt + + Parameters: + + Input, floating_point_t X, Y, the quantities to compare. + + Output, floating_point_t R8_MAX, the maximum of X and Y. +*/ +{ + floating_point_t value; + + if (y < x) { + value = x; + } else { + value = y; + } + return value; +} +/******************************************************************************/ + +floating_point_t r8_random(int iseed[4]) + +/******************************************************************************/ +/* + Purpose: + + R8_RANDOM returns a uniformly distributed random number between 0 and 1. + + Discussion: + + This routine uses a multiplicative congruential method with modulus + 2**48 and multiplier 33952834046453 (see G.S.Fishman, + 'Multiplicative congruential random number generators with modulus + 2**b: an exhaustive analysis for b = 32 and a partial analysis for + b = 48', Math. Comp. 189, pp 331-344, 1990). + + 48-bit integers are stored in 4 integer array elements with 12 bits + per element. Hence the routine is portable across machines with + integers of 32 bits or more. + + Parameters: + + Input/output, integer ISEED(4). + On entry, the seed of the random number generator; the array + elements must be between 0 and 4095, and ISEED(4) must be odd. + On exit, the seed is updated. + + Output, floating_point_t R8_RANDOM, the next pseudorandom number. +*/ +{ + int ipw2 = 4096; + int it1; + int it2; + int it3; + int it4; + int m1 = 494; + int m2 = 322; + int m3 = 2508; + int m4 = 2549; + floating_point_t r = 1.0 / 4096.0; + floating_point_t value; + /* + Multiply the seed by the multiplier modulo 2**48. +*/ + it4 = iseed[3] * m4; + it3 = it4 / ipw2; + it4 = it4 - ipw2 * it3; + it3 = it3 + iseed[2] * m4 + iseed[3] * m3; + it2 = it3 / ipw2; + it3 = it3 - ipw2 * it2; + it2 = it2 + iseed[1] * m4 + iseed[2] * m3 + iseed[3] * m2; + it1 = it2 / ipw2; + it2 = it2 - ipw2 * it1; + it1 = it1 + iseed[0] * m4 + iseed[1] * m3 + iseed[2] * m2 + iseed[3] * m1; + it1 = (it1 % ipw2); + /* + Return updated seed +*/ + iseed[0] = it1; + iseed[1] = it2; + iseed[2] = it3; + iseed[3] = it4; + /* + Convert 48-bit integer to a real number in the interval (0,1) +*/ + value = r * ((floating_point_t)(it1) + r * ((floating_point_t)(it2) + r * ((floating_point_t)(it3) + r * ((floating_point_t)(it4))))); + + return value; +} +/******************************************************************************/ + +void r8mat_gen(int lda, int n, floating_point_t *a) + +/******************************************************************************/ +/* + Purpose: + + R8MAT_GEN generates a random R8MAT. + + Modified: + + 06 June 2005 + + Parameters: + + Input, integer LDA, the leading dimension of the matrix. + + Input, integer N, the order of the matrix. + + Output, floating_point_t R8MAT_GEN[LDA*N], the N by N matrix. +*/ +{ + int i; + int init[4] = {1, 2, 3, 1325}; + int j; + + for (j = 1; j <= n; j++) { + for (i = 1; i <= n; i++) { + a[i - 1 + (j - 1) * lda] = r8_random(init) - 0.5; + } + } +} +/******************************************************************************/ diff --git a/tests/performance/linpack_float/test_linpack_float.py b/tests/performance/linpack_float/test_linpack_float.py new file mode 100644 index 00000000000..d11f6c74136 --- /dev/null +++ b/tests/performance/linpack_float/test_linpack_float.py @@ -0,0 +1,61 @@ +import json +import logging +import os + + +def test_linpack_float(dut, request): + LOGGER = logging.getLogger(__name__) + + # Match "Runs: %d" + res = dut.expect(r"Runs: (\d+)", timeout=60) + runs = int(res.group(0).decode("utf-8").split(" ")[1]) + LOGGER.info("Number of runs: {}".format(runs)) + assert runs > 0, "Invalid number of runs" + + # Match "Type: %s" + res = dut.expect(r"Type: (\w+)", timeout=60) + data_type = res.group(0).decode("utf-8").split(" ")[1] + LOGGER.info("Data type: {}".format(data_type)) + assert data_type == "float", "Invalid data type" + + # Match "Runs completed: %d" + res = dut.expect(r"Runs completed: (\d+)", timeout=120) + runs_completed = int(res.group(0).decode("utf-8").split(" ")[2]) + LOGGER.info("Runs completed: {}".format(runs_completed)) + assert runs_completed == runs, "Invalid number of runs completed" + + # Match "Average MFLOPS: %f" + res = dut.expect(r"Average MFLOPS: (\d+\.\d+)", timeout=120) + avg_score = float(res.group(0).decode("utf-8").split(" ")[2]) + LOGGER.info("Average MFLOPS: {}".format(avg_score)) + assert avg_score > 0, "Invalid average MFLOPS" + + # Match "Min MFLOPS: %f" + res = dut.expect(r"Min MFLOPS: (\d+\.\d+)", timeout=120) + min_score = float(res.group(0).decode("utf-8").split(" ")[2]) + LOGGER.info("Min MFLOPS: {}".format(min_score)) + assert min_score > 0 and min_score < 1000000000.0, "Invalid min MFLOPS" + + # Match "Max MFLOPS: %f" + res = dut.expect(r"Max MFLOPS: (\d+\.\d+)", timeout=120) + max_score = float(res.group(0).decode("utf-8").split(" ")[2]) + LOGGER.info("Max MFLOPS: {}".format(max_score)) + assert max_score > 0, "Invalid max MFLOPS" + + # Create JSON with results and write it to file + # Always create a JSON with this format (so it can be merged later on): + # { TEST_NAME_STR: TEST_RESULTS_DICT } + results = {"linpack_float": {"runs": runs, "avg_score": avg_score, "min_score": min_score, "max_score": max_score}} + + current_folder = os.path.dirname(request.path) + file_index = 0 + report_file = os.path.join(current_folder, "result_linpack_float" + str(file_index) + ".json") + while os.path.exists(report_file): + report_file = report_file.replace(str(file_index) + ".json", str(file_index + 1) + ".json") + file_index += 1 + + with open(report_file, "w") as f: + try: + f.write(json.dumps(results)) + except Exception as e: + LOGGER.warning("Failed to write results to file: {}".format(e)) From 5fd7826d9f2847041a1fe5391612f41e6410743e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Fri, 4 Oct 2024 12:52:07 +0200 Subject: [PATCH 044/406] fix(boards): Remove partition scheme from FlashSize (#10400) --- boards.txt | 122 ----------------------------------------------------- 1 file changed, 122 deletions(-) diff --git a/boards.txt b/boards.txt index c785e4d80a4..c73d81b6f31 100644 --- a/boards.txt +++ b/boards.txt @@ -123,7 +123,6 @@ esp32c2.menu.FlashFreq.30.build.flash_freq=30m esp32c2.menu.FlashSize.2M=2MB (16Mb) esp32c2.menu.FlashSize.2M.build.flash_size=2MB -esp32c2.menu.FlashSize.2M.build.partitions=minimal esp32c2.menu.FlashSize.4M=4MB (32Mb) esp32c2.menu.FlashSize.4M.build.flash_size=4MB @@ -293,10 +292,8 @@ esp32h2.menu.FlashSize.4M=4MB (32Mb) esp32h2.menu.FlashSize.4M.build.flash_size=4MB esp32h2.menu.FlashSize.8M=8MB (64Mb) esp32h2.menu.FlashSize.8M.build.flash_size=8MB -esp32h2.menu.FlashSize.8M.build.partitions=default_8MB esp32h2.menu.FlashSize.2M=2MB (16Mb) esp32h2.menu.FlashSize.2M.build.flash_size=2MB -esp32h2.menu.FlashSize.2M.build.partitions=minimal esp32h2.menu.FlashSize.16M=16MB (128Mb) esp32h2.menu.FlashSize.16M.build.flash_size=16MB @@ -487,10 +484,8 @@ esp32c6.menu.FlashSize.4M=4MB (32Mb) esp32c6.menu.FlashSize.4M.build.flash_size=4MB esp32c6.menu.FlashSize.8M=8MB (64Mb) esp32c6.menu.FlashSize.8M.build.flash_size=8MB -esp32c6.menu.FlashSize.8M.build.partitions=default_8MB esp32c6.menu.FlashSize.2M=2MB (16Mb) esp32c6.menu.FlashSize.2M.build.flash_size=2MB -esp32c6.menu.FlashSize.2M.build.partitions=minimal esp32c6.menu.FlashSize.16M=16MB (128Mb) esp32c6.menu.FlashSize.16M.build.flash_size=16MB @@ -634,12 +629,10 @@ esp32s3.menu.FlashSize.4M=4MB (32Mb) esp32s3.menu.FlashSize.4M.build.flash_size=4MB esp32s3.menu.FlashSize.8M=8MB (64Mb) esp32s3.menu.FlashSize.8M.build.flash_size=8MB -esp32s3.menu.FlashSize.8M.build.partitions=default_8MB esp32s3.menu.FlashSize.16M=16MB (128Mb) esp32s3.menu.FlashSize.16M.build.flash_size=16MB esp32s3.menu.FlashSize.32M=32MB (256Mb) esp32s3.menu.FlashSize.32M.build.flash_size=32MB -esp32s3.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB esp32s3.menu.LoopCore.1=Core 1 esp32s3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -928,10 +921,8 @@ esp32c3.menu.FlashSize.4M=4MB (32Mb) esp32c3.menu.FlashSize.4M.build.flash_size=4MB esp32c3.menu.FlashSize.8M=8MB (64Mb) esp32c3.menu.FlashSize.8M.build.flash_size=8MB -esp32c3.menu.FlashSize.8M.build.partitions=default_8MB esp32c3.menu.FlashSize.2M=2MB (16Mb) esp32c3.menu.FlashSize.2M.build.flash_size=2MB -esp32c3.menu.FlashSize.2M.build.partitions=minimal esp32c3.menu.FlashSize.16M=16MB (128Mb) esp32c3.menu.FlashSize.16M.build.flash_size=16MB @@ -1137,10 +1128,8 @@ esp32s2.menu.FlashSize.4M=4MB (32Mb) esp32s2.menu.FlashSize.4M.build.flash_size=4MB esp32s2.menu.FlashSize.8M=8MB (64Mb) esp32s2.menu.FlashSize.8M.build.flash_size=8MB -esp32s2.menu.FlashSize.8M.build.partitions=default_8MB esp32s2.menu.FlashSize.2M=2MB (16Mb) esp32s2.menu.FlashSize.2M.build.flash_size=2MB -esp32s2.menu.FlashSize.2M.build.partitions=minimal esp32s2.menu.FlashSize.16M=16MB (128Mb) esp32s2.menu.FlashSize.16M.build.flash_size=16MB @@ -1323,10 +1312,8 @@ esp32.menu.FlashSize.4M=4MB (32Mb) esp32.menu.FlashSize.4M.build.flash_size=4MB esp32.menu.FlashSize.8M=8MB (64Mb) esp32.menu.FlashSize.8M.build.flash_size=8MB -esp32.menu.FlashSize.8M.build.partitions=default_8MB esp32.menu.FlashSize.2M=2MB (16Mb) esp32.menu.FlashSize.2M.build.flash_size=2MB -esp32.menu.FlashSize.2M.build.partitions=minimal esp32.menu.FlashSize.16M=16MB (128Mb) esp32.menu.FlashSize.16M.build.flash_size=16MB @@ -1499,7 +1486,6 @@ esp32da.menu.FlashSize.4M=4MB (32Mb) esp32da.menu.FlashSize.4M.build.flash_size=4MB esp32da.menu.FlashSize.8M=8MB (64Mb) esp32da.menu.FlashSize.8M.build.flash_size=8MB -esp32da.menu.FlashSize.8M.build.partitions=default_8MB esp32da.menu.FlashSize.16M=16MB (128Mb) esp32da.menu.FlashSize.16M.build.flash_size=16MB @@ -1841,12 +1827,10 @@ esp32s3-octal.menu.FlashSize.4M=4MB (32Mb) esp32s3-octal.menu.FlashSize.4M.build.flash_size=4MB esp32s3-octal.menu.FlashSize.8M=8MB (64Mb) esp32s3-octal.menu.FlashSize.8M.build.flash_size=8MB -esp32s3-octal.menu.FlashSize.8M.build.partitions=default_8MB esp32s3-octal.menu.FlashSize.16M=16MB (128Mb) esp32s3-octal.menu.FlashSize.16M.build.flash_size=16MB esp32s3-octal.menu.FlashSize.32M=32MB (256Mb) esp32s3-octal.menu.FlashSize.32M.build.flash_size=32MB -esp32s3-octal.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB esp32s3-octal.menu.LoopCore.1=Core 1 esp32s3-octal.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -2367,7 +2351,6 @@ esp32s2usb.menu.FlashSize.4M=4MB (32Mb) esp32s2usb.menu.FlashSize.4M.build.flash_size=4MB esp32s2usb.menu.FlashSize.8M=8MB (64Mb) esp32s2usb.menu.FlashSize.8M.build.flash_size=8MB -esp32s2usb.menu.FlashSize.8M.build.partitions=default_8MB esp32s2usb.menu.FlashSize.16M=16MB (128Mb) esp32s2usb.menu.FlashSize.16M.build.flash_size=16MB @@ -2461,13 +2444,10 @@ esp32wroverkit.menu.FlashSize.4M=4MB (32Mb) esp32wroverkit.menu.FlashSize.4M.build.flash_size=4MB esp32wroverkit.menu.FlashSize.8M=8MB (64Mb) esp32wroverkit.menu.FlashSize.8M.build.flash_size=8MB -esp32wroverkit.menu.FlashSize.8M.build.partitions=default_8MB esp32wroverkit.menu.FlashSize.2M=2MB (16Mb) esp32wroverkit.menu.FlashSize.2M.build.flash_size=2MB -esp32wroverkit.menu.FlashSize.2M.build.partitions=minimal esp32wroverkit.menu.FlashSize.16M=16MB (128Mb) esp32wroverkit.menu.FlashSize.16M.build.flash_size=16MB -esp32wroverkit.menu.FlashSize.16M.build.partitions=default_16MB esp32wroverkit.menu.PSRAM.enabled=Enabled esp32wroverkit.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw @@ -3069,10 +3049,8 @@ um_feathers2.menu.FlashSize.4M=4MB (32Mb) um_feathers2.menu.FlashSize.4M.build.flash_size=4MB um_feathers2.menu.FlashSize.8M=8MB (64Mb) um_feathers2.menu.FlashSize.8M.build.flash_size=8MB -um_feathers2.menu.FlashSize.8M.build.partitions=default_8MB um_feathers2.menu.FlashSize.2M=2MB (16Mb) um_feathers2.menu.FlashSize.2M.build.flash_size=2MB -um_feathers2.menu.FlashSize.2M.build.partitions=minimal um_feathers2.menu.UploadSpeed.921600=921600 um_feathers2.menu.UploadSpeed.921600.upload.speed=921600 @@ -3211,7 +3189,6 @@ um_feathers2neo.menu.FlashSize.4M=4MB (32Mb) um_feathers2neo.menu.FlashSize.4M.build.flash_size=4MB um_feathers2neo.menu.FlashSize.2M=2MB (16Mb) um_feathers2neo.menu.FlashSize.2M.build.flash_size=2MB -um_feathers2neo.menu.FlashSize.2M.build.partitions=minimal um_feathers2neo.menu.UploadSpeed.921600=921600 um_feathers2neo.menu.UploadSpeed.921600.upload.speed=921600 @@ -4246,7 +4223,6 @@ um_tinyc6.menu.FlashFreq.40.build.flash_freq=40m um_tinyc6.menu.FlashSize.8M=8MB (64Mb) um_tinyc6.menu.FlashSize.8M.build.flash_size=8MB -um_tinyc6.menu.FlashSize.8M.build.partitions=default_8MB um_tinyc6.menu.UploadSpeed.921600=921600 um_tinyc6.menu.UploadSpeed.921600.upload.speed=921600 @@ -4400,7 +4376,6 @@ um_tinys2.menu.FlashSize.4M=4MB (32Mb) um_tinys2.menu.FlashSize.4M.build.flash_size=4MB um_tinys2.menu.FlashSize.2M=2MB (16Mb) um_tinys2.menu.FlashSize.2M.build.flash_size=2MB -um_tinys2.menu.FlashSize.2M.build.partitions=minimal um_tinys2.menu.UploadSpeed.921600=921600 um_tinys2.menu.UploadSpeed.921600.upload.speed=921600 @@ -5669,10 +5644,8 @@ micros2.menu.FlashSize.4M=4MB (32Mb) micros2.menu.FlashSize.4M.build.flash_size=4MB micros2.menu.FlashSize.8M=8MB (64Mb) micros2.menu.FlashSize.8M.build.flash_size=8MB -micros2.menu.FlashSize.8M.build.partitions=default_8MB micros2.menu.FlashSize.2M=2MB (16Mb) micros2.menu.FlashSize.2M.build.flash_size=2MB -micros2.menu.FlashSize.2M.build.partitions=minimal micros2.menu.UploadSpeed.921600=921600 micros2.menu.UploadSpeed.921600.upload.speed=921600 @@ -6003,10 +5976,8 @@ ttgo-t1.menu.FlashSize.4M=4MB (32Mb) ttgo-t1.menu.FlashSize.4M.build.flash_size=4MB ttgo-t1.menu.FlashSize.2M=2MB (16Mb) ttgo-t1.menu.FlashSize.2M.build.flash_size=2MB -ttgo-t1.menu.FlashSize.2M.build.partitions=minimal ttgo-t1.menu.FlashSize.16M=16MB (128Mb) ttgo-t1.menu.FlashSize.16M.build.flash_size=16MB -ttgo-t1.menu.FlashSize.16M.build.partitions=ffat ttgo-t1.menu.UploadSpeed.921600=921600 ttgo-t1.menu.UploadSpeed.921600.upload.speed=921600 @@ -6463,7 +6434,6 @@ cw02.menu.FlashSize.4M=4MB (32Mb) cw02.menu.FlashSize.4M.build.flash_size=4MB cw02.menu.FlashSize.2M=2MB (16Mb) cw02.menu.FlashSize.2M.build.flash_size=2MB -cw02.menu.FlashSize.2M.build.partitions=minimal cw02.menu.UploadSpeed.921600=921600 cw02.menu.UploadSpeed.921600.upload.speed=921600 @@ -6864,10 +6834,8 @@ sparkfun_esp32s2_thing_plus.menu.FlashSize.4M=4MB (32Mb) sparkfun_esp32s2_thing_plus.menu.FlashSize.4M.build.flash_size=4MB sparkfun_esp32s2_thing_plus.menu.FlashSize.8M=8MB (64Mb) sparkfun_esp32s2_thing_plus.menu.FlashSize.8M.build.flash_size=8MB -sparkfun_esp32s2_thing_plus.menu.FlashSize.8M.build.partitions=default_8MB sparkfun_esp32s2_thing_plus.menu.FlashSize.2M=2MB (16Mb) sparkfun_esp32s2_thing_plus.menu.FlashSize.2M.build.flash_size=2MB -sparkfun_esp32s2_thing_plus.menu.FlashSize.2M.build.partitions=minimal sparkfun_esp32s2_thing_plus.menu.FlashSize.16M=16MB (128Mb) sparkfun_esp32s2_thing_plus.menu.FlashSize.16M.build.flash_size=16MB @@ -7256,10 +7224,8 @@ sparkfun_esp32c6_thing_plus.menu.FlashSize.4M=4MB (32Mb) sparkfun_esp32c6_thing_plus.menu.FlashSize.4M.build.flash_size=4MB sparkfun_esp32c6_thing_plus.menu.FlashSize.8M=8MB (64Mb) sparkfun_esp32c6_thing_plus.menu.FlashSize.8M.build.flash_size=8MB -sparkfun_esp32c6_thing_plus.menu.FlashSize.8M.build.partitions=default_8MB sparkfun_esp32c6_thing_plus.menu.FlashSize.2M=2MB (16Mb) sparkfun_esp32c6_thing_plus.menu.FlashSize.2M.build.flash_size=2MB -sparkfun_esp32c6_thing_plus.menu.FlashSize.2M.build.partitions=minimal sparkfun_esp32c6_thing_plus.menu.FlashSize.16M=16MB (128Mb) sparkfun_esp32c6_thing_plus.menu.FlashSize.16M.build.flash_size=16MB @@ -7417,10 +7383,8 @@ esp32micromod.menu.FlashSize.4M=4MB (32Mb) esp32micromod.menu.FlashSize.4M.build.flash_size=4MB esp32micromod.menu.FlashSize.8M=8MB (64Mb) esp32micromod.menu.FlashSize.8M.build.flash_size=8MB -esp32micromod.menu.FlashSize.8M.build.partitions=default_8MB esp32micromod.menu.FlashSize.2M=2MB (16Mb) esp32micromod.menu.FlashSize.2M.build.flash_size=2MB -esp32micromod.menu.FlashSize.2M.build.partitions=minimal esp32micromod.menu.FlashSize.16M=16MB (128Mb) esp32micromod.menu.FlashSize.16M.build.flash_size=16MB @@ -7670,10 +7634,8 @@ sparkfun_esp32_iot_redboard.menu.FlashSize.4M=4MB (32Mb) sparkfun_esp32_iot_redboard.menu.FlashSize.4M.build.flash_size=4MB sparkfun_esp32_iot_redboard.menu.FlashSize.8M=8MB (64Mb) sparkfun_esp32_iot_redboard.menu.FlashSize.8M.build.flash_size=8MB -sparkfun_esp32_iot_redboard.menu.FlashSize.8M.build.partitions=default_8MB sparkfun_esp32_iot_redboard.menu.FlashSize.2M=2MB (16Mb) sparkfun_esp32_iot_redboard.menu.FlashSize.2M.build.flash_size=2MB -sparkfun_esp32_iot_redboard.menu.FlashSize.2M.build.partitions=minimal sparkfun_esp32_iot_redboard.menu.FlashSize.16M=16MB (128Mb) sparkfun_esp32_iot_redboard.menu.FlashSize.16M.build.flash_size=16MB @@ -7855,10 +7817,8 @@ sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.4M=4MB (32Mb) sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.4M.build.flash_size=4MB sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.8M=8MB (64Mb) sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.8M.build.flash_size=8MB -sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.8M.build.partitions=default_8MB sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.2M=2MB (16Mb) sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.2M.build.flash_size=2MB -sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.2M.build.partitions=minimal sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.16M=16MB (128Mb) sparkfun_esp32c6_qwiic_pocket.menu.FlashSize.16M.build.flash_size=16MB @@ -8111,13 +8071,10 @@ nina_w10.menu.UploadSpeed.512000.upload.speed=512000 nina_w10.menu.FlashSize.2M=2MB (16Mb, NINA-W101/W102) nina_w10.menu.FlashSize.2M.build.flash_size=2MB -nina_w10.menu.FlashSize.2M.build.partitions=minimal nina_w10.menu.FlashSize.4M=4MB (32Mb, NINA-W106-00B) nina_w10.menu.FlashSize.4M.build.flash_size=4MB -nina_w10.menu.FlashSize.4M.build.partitions=default nina_w10.menu.FlashSize.8M=8MB (64Mb, NINA-W106-10B) nina_w10.menu.FlashSize.8M.build.flash_size=8MB -nina_w10.menu.FlashSize.8M.build.partitions=default_8MB nina_w10.menu.FlashFreq.80=80MHz nina_w10.menu.FlashFreq.80.build.flash_freq=80m @@ -8287,7 +8244,6 @@ nora_w10.menu.FlashSize.4M=4MB (32Mb) nora_w10.menu.FlashSize.4M.build.flash_size=4MB nora_w10.menu.FlashSize.8M=8MB (64Mb) nora_w10.menu.FlashSize.8M.build.flash_size=8MB -nora_w10.menu.FlashSize.8M.build.partitions=default_8MB #nora_w10.menu.FlashSize.16M=16MB (128Mb) #nora_w10.menu.FlashSize.16M.build.flash_size=16MB #nora_w10.menu.FlashSize.32M=32MB (256Mb) @@ -11261,10 +11217,8 @@ dfrobot_firebeetle2_esp32e.menu.FlashSize.4M=4MB (32Mb) dfrobot_firebeetle2_esp32e.menu.FlashSize.4M.build.flash_size=4MB dfrobot_firebeetle2_esp32e.menu.FlashSize.8M=8MB (64Mb) dfrobot_firebeetle2_esp32e.menu.FlashSize.8M.build.flash_size=8MB -dfrobot_firebeetle2_esp32e.menu.FlashSize.8M.build.partitions=default_8MB dfrobot_firebeetle2_esp32e.menu.FlashSize.2M=2MB (16Mb) dfrobot_firebeetle2_esp32e.menu.FlashSize.2M.build.flash_size=2MB -dfrobot_firebeetle2_esp32e.menu.FlashSize.2M.build.partitions=minimal dfrobot_firebeetle2_esp32e.menu.FlashSize.16M=16MB (128Mb) dfrobot_firebeetle2_esp32e.menu.FlashSize.16M.build.flash_size=16MB @@ -11398,7 +11352,6 @@ dfrobot_firebeetle2_esp32s3.menu.FlashSize.4M=4MB (32Mb) dfrobot_firebeetle2_esp32s3.menu.FlashSize.4M.build.flash_size=4MB dfrobot_firebeetle2_esp32s3.menu.FlashSize.8M=8MB (64Mb) dfrobot_firebeetle2_esp32s3.menu.FlashSize.8M.build.flash_size=8MB -dfrobot_firebeetle2_esp32s3.menu.FlashSize.8M.build.partitions=default_8MB dfrobot_firebeetle2_esp32s3.menu.FlashSize.16M=16MB (128Mb) dfrobot_firebeetle2_esp32s3.menu.FlashSize.16M.build.flash_size=16MB #dfrobot_firebeetle2_esp32s3.menu.FlashSize.32M=32MB (256Mb) @@ -16564,7 +16517,6 @@ nologo_esp32s3_pico.menu.FlashMode.opi.build.flash_freq=80m nologo_esp32s3_pico.menu.FlashSize.8M=8MB (64Mb) nologo_esp32s3_pico.menu.FlashSize.8M.build.flash_size=8MB -nologo_esp32s3_pico.menu.FlashSize.8M.build.partitions=default_8MB nologo_esp32s3_pico.menu.FlashSize.16M=16MB (128Mb) nologo_esp32s3_pico.menu.FlashSize.16M.build.flash_size=16MB @@ -17826,10 +17778,8 @@ esp32s2-devkitlipo.menu.FlashSize.4M=4MB (32Mb) esp32s2-devkitlipo.menu.FlashSize.4M.build.flash_size=4MB esp32s2-devkitlipo.menu.FlashSize.8M=8MB (64Mb) esp32s2-devkitlipo.menu.FlashSize.8M.build.flash_size=8MB -esp32s2-devkitlipo.menu.FlashSize.8M.build.partitions=default_8MB esp32s2-devkitlipo.menu.FlashSize.2M=2MB (16Mb) esp32s2-devkitlipo.menu.FlashSize.2M.build.flash_size=2MB -esp32s2-devkitlipo.menu.FlashSize.2M.build.partitions=minimal esp32s2-devkitlipo.menu.FlashSize.16M=16MB (128Mb) esp32s2-devkitlipo.menu.FlashSize.16M.build.flash_size=16MB @@ -18023,10 +17973,8 @@ esp32s2-devkitlipo-usb.menu.FlashSize.4M=4MB (32Mb) esp32s2-devkitlipo-usb.menu.FlashSize.4M.build.flash_size=4MB esp32s2-devkitlipo-usb.menu.FlashSize.8M=8MB (64Mb) esp32s2-devkitlipo-usb.menu.FlashSize.8M.build.flash_size=8MB -esp32s2-devkitlipo-usb.menu.FlashSize.8M.build.partitions=default_8MB esp32s2-devkitlipo-usb.menu.FlashSize.2M=2MB (16Mb) esp32s2-devkitlipo-usb.menu.FlashSize.2M.build.flash_size=2MB -esp32s2-devkitlipo-usb.menu.FlashSize.2M.build.partitions=minimal esp32s2-devkitlipo-usb.menu.FlashSize.16M=16MB (128Mb) esp32s2-devkitlipo-usb.menu.FlashSize.16M.build.flash_size=16MB @@ -18157,12 +18105,10 @@ esp32s3-devkitlipo.menu.FlashSize.4M=4MB (32Mb) esp32s3-devkitlipo.menu.FlashSize.4M.build.flash_size=4MB esp32s3-devkitlipo.menu.FlashSize.8M=8MB (64Mb) esp32s3-devkitlipo.menu.FlashSize.8M.build.flash_size=8MB -esp32s3-devkitlipo.menu.FlashSize.8M.build.partitions=default_8MB esp32s3-devkitlipo.menu.FlashSize.16M=16MB (128Mb) esp32s3-devkitlipo.menu.FlashSize.16M.build.flash_size=16MB esp32s3-devkitlipo.menu.FlashSize.32M=32MB (256Mb) esp32s3-devkitlipo.menu.FlashSize.32M.build.flash_size=32MB -esp32s3-devkitlipo.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB esp32s3-devkitlipo.menu.LoopCore.1=Core 1 esp32s3-devkitlipo.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -18438,10 +18384,8 @@ esp32c3-devkitlipo.menu.FlashSize.4M=4MB (32Mb) esp32c3-devkitlipo.menu.FlashSize.4M.build.flash_size=4MB esp32c3-devkitlipo.menu.FlashSize.8M=8MB (64Mb) esp32c3-devkitlipo.menu.FlashSize.8M.build.flash_size=8MB -esp32c3-devkitlipo.menu.FlashSize.8M.build.partitions=default_8MB esp32c3-devkitlipo.menu.FlashSize.2M=2MB (16Mb) esp32c3-devkitlipo.menu.FlashSize.2M.build.flash_size=2MB -esp32c3-devkitlipo.menu.FlashSize.2M.build.partitions=minimal esp32c3-devkitlipo.menu.FlashSize.16M=16MB (128Mb) esp32c3-devkitlipo.menu.FlashSize.16M.build.flash_size=16MB @@ -18613,10 +18557,8 @@ esp32c6-evb.menu.FlashSize.4M=4MB (32Mb) esp32c6-evb.menu.FlashSize.4M.build.flash_size=4MB esp32c6-evb.menu.FlashSize.8M=8MB (64Mb) esp32c6-evb.menu.FlashSize.8M.build.flash_size=8MB -esp32c6-evb.menu.FlashSize.8M.build.partitions=default_8MB esp32c6-evb.menu.FlashSize.2M=2MB (16Mb) esp32c6-evb.menu.FlashSize.2M.build.flash_size=2MB -esp32c6-evb.menu.FlashSize.2M.build.partitions=minimal esp32c6-evb.menu.FlashSize.16M=16MB (128Mb) esp32c6-evb.menu.FlashSize.16M.build.flash_size=16MB @@ -18795,10 +18737,8 @@ esp32h2-devkitlipo.menu.FlashSize.4M=4MB (32Mb) esp32h2-devkitlipo.menu.FlashSize.4M.build.flash_size=4MB esp32h2-devkitlipo.menu.FlashSize.8M=8MB (64Mb) esp32h2-devkitlipo.menu.FlashSize.8M.build.flash_size=8MB -esp32h2-devkitlipo.menu.FlashSize.8M.build.partitions=default_8MB esp32h2-devkitlipo.menu.FlashSize.2M=2MB (16Mb) esp32h2-devkitlipo.menu.FlashSize.2M.build.flash_size=2MB -esp32h2-devkitlipo.menu.FlashSize.2M.build.partitions=minimal esp32h2-devkitlipo.menu.FlashSize.16M=16MB (128Mb) esp32h2-devkitlipo.menu.FlashSize.16M.build.flash_size=16MB @@ -18984,10 +18924,8 @@ esp32-sbc-fabgl.menu.FlashSize.4M=4MB (32Mb) esp32-sbc-fabgl.menu.FlashSize.4M.build.flash_size=4MB esp32-sbc-fabgl.menu.FlashSize.8M=8MB (64Mb) esp32-sbc-fabgl.menu.FlashSize.8M.build.flash_size=8MB -esp32-sbc-fabgl.menu.FlashSize.8M.build.partitions=default_8MB esp32-sbc-fabgl.menu.FlashSize.2M=2MB (16Mb) esp32-sbc-fabgl.menu.FlashSize.2M.build.flash_size=2MB -esp32-sbc-fabgl.menu.FlashSize.2M.build.partitions=minimal esp32-sbc-fabgl.menu.FlashSize.16M=16MB (128Mb) esp32-sbc-fabgl.menu.FlashSize.16M.build.flash_size=16MB @@ -20686,7 +20624,6 @@ m5stack_atoms3.menu.FlashMode.opi.build.flash_freq=80m m5stack_atoms3.menu.FlashSize.8M=8MB (64Mb) m5stack_atoms3.menu.FlashSize.8M.build.flash_size=8MB -m5stack_atoms3.menu.FlashSize.8M.build.partitions=default_8MB m5stack_atoms3.menu.LoopCore.1=Core 1 m5stack_atoms3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -20920,7 +20857,6 @@ m5stack_cores3.menu.FlashSize.16M=16MB (128Mb) m5stack_cores3.menu.FlashSize.16M.build.flash_size=16MB m5stack_cores3.menu.FlashSize.32M=32MB (256Mb) m5stack_cores3.menu.FlashSize.32M.build.flash_size=32MB -m5stack_cores3.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB m5stack_cores3.menu.LoopCore.1=Core 1 m5stack_cores3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -21463,7 +21399,6 @@ m5stack_unit_cams3.menu.FlashSize.16M=16MB (128Mb) m5stack_unit_cams3.menu.FlashSize.16M.build.flash_size=16MB m5stack_unit_cams3.menu.FlashSize.32M=32MB (256Mb) m5stack_unit_cams3.menu.FlashSize.32M.build.flash_size=32MB -m5stack_unit_cams3.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB m5stack_unit_cams3.menu.LoopCore.1=Core 1 m5stack_unit_cams3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -22475,12 +22410,10 @@ m5stack_stamp_s3.menu.FlashSize.4M=4MB (32Mb) m5stack_stamp_s3.menu.FlashSize.4M.build.flash_size=4MB m5stack_stamp_s3.menu.FlashSize.8M=8MB (64Mb) m5stack_stamp_s3.menu.FlashSize.8M.build.flash_size=8MB -m5stack_stamp_s3.menu.FlashSize.8M.build.partitions=default_8MB m5stack_stamp_s3.menu.FlashSize.16M=16MB (128Mb) m5stack_stamp_s3.menu.FlashSize.16M.build.flash_size=16MB m5stack_stamp_s3.menu.FlashSize.32M=32MB (256Mb) m5stack_stamp_s3.menu.FlashSize.32M.build.flash_size=32MB -m5stack_stamp_s3.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB m5stack_stamp_s3.menu.LoopCore.1=Core 1 m5stack_stamp_s3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -22714,12 +22647,10 @@ m5stack_capsule.menu.FlashSize.4M=4MB (32Mb) m5stack_capsule.menu.FlashSize.4M.build.flash_size=4MB m5stack_capsule.menu.FlashSize.8M=8MB (64Mb) m5stack_capsule.menu.FlashSize.8M.build.flash_size=8MB -m5stack_capsule.menu.FlashSize.8M.build.partitions=default_8MB m5stack_capsule.menu.FlashSize.16M=16MB (128Mb) m5stack_capsule.menu.FlashSize.16M.build.flash_size=16MB m5stack_capsule.menu.FlashSize.32M=32MB (256Mb) m5stack_capsule.menu.FlashSize.32M.build.flash_size=32MB -m5stack_capsule.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB m5stack_capsule.menu.LoopCore.1=Core 1 m5stack_capsule.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -22956,12 +22887,10 @@ m5stack_cardputer.menu.FlashSize.4M=4MB (32Mb) m5stack_cardputer.menu.FlashSize.4M.build.flash_size=4MB m5stack_cardputer.menu.FlashSize.8M=8MB (64Mb) m5stack_cardputer.menu.FlashSize.8M.build.flash_size=8MB -m5stack_cardputer.menu.FlashSize.8M.build.partitions=default_8MB m5stack_cardputer.menu.FlashSize.16M=16MB (128Mb) m5stack_cardputer.menu.FlashSize.16M.build.flash_size=16MB m5stack_cardputer.menu.FlashSize.32M=32MB (256Mb) m5stack_cardputer.menu.FlashSize.32M.build.flash_size=32MB -m5stack_cardputer.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB m5stack_cardputer.menu.LoopCore.1=Core 1 m5stack_cardputer.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -23195,12 +23124,10 @@ m5stack_dial.menu.FlashSize.4M=4MB (32Mb) m5stack_dial.menu.FlashSize.4M.build.flash_size=4MB m5stack_dial.menu.FlashSize.8M=8MB (64Mb) m5stack_dial.menu.FlashSize.8M.build.flash_size=8MB -m5stack_dial.menu.FlashSize.8M.build.partitions=default_8MB m5stack_dial.menu.FlashSize.16M=16MB (128Mb) m5stack_dial.menu.FlashSize.16M.build.flash_size=16MB m5stack_dial.menu.FlashSize.32M=32MB (256Mb) m5stack_dial.menu.FlashSize.32M.build.flash_size=32MB -m5stack_dial.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB m5stack_dial.menu.LoopCore.1=Core 1 m5stack_dial.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -23434,12 +23361,10 @@ m5stack_dinmeter.menu.FlashSize.4M=4MB (32Mb) m5stack_dinmeter.menu.FlashSize.4M.build.flash_size=4MB m5stack_dinmeter.menu.FlashSize.8M=8MB (64Mb) m5stack_dinmeter.menu.FlashSize.8M.build.flash_size=8MB -m5stack_dinmeter.menu.FlashSize.8M.build.partitions=default_8MB m5stack_dinmeter.menu.FlashSize.16M=16MB (128Mb) m5stack_dinmeter.menu.FlashSize.16M.build.flash_size=16MB m5stack_dinmeter.menu.FlashSize.32M=32MB (256Mb) m5stack_dinmeter.menu.FlashSize.32M.build.flash_size=32MB -m5stack_dinmeter.menu.FlashSize.32M.build.partitions=app5M_fat24M_32MB m5stack_dinmeter.menu.LoopCore.1=Core 1 m5stack_dinmeter.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -26516,7 +26441,6 @@ espectro32.menu.FlashSize.4M=4MB (32Mb) espectro32.menu.FlashSize.4M.build.flash_size=4MB espectro32.menu.FlashSize.2M=2MB (16Mb) espectro32.menu.FlashSize.2M.build.flash_size=2MB -espectro32.menu.FlashSize.2M.build.partitions=minimal espectro32.menu.UploadSpeed.921600=921600 espectro32.menu.UploadSpeed.921600.upload.speed=921600 @@ -26745,10 +26669,8 @@ alksesp32.menu.FlashSize.4M=4MB (32Mb) alksesp32.menu.FlashSize.4M.build.flash_size=4MB alksesp32.menu.FlashSize.2M=2MB (16Mb) alksesp32.menu.FlashSize.2M.build.flash_size=2MB -alksesp32.menu.FlashSize.2M.build.partitions=minimal alksesp32.menu.FlashSize.16M=16MB (128Mb) alksesp32.menu.FlashSize.16M.build.flash_size=16MB -alksesp32.menu.FlashSize.16M.build.partitions=ffat alksesp32.menu.UploadSpeed.921600=921600 alksesp32.menu.UploadSpeed.921600.upload.speed=921600 @@ -27265,7 +27187,6 @@ bpi_leaf_s3.menu.FlashMode.opi.build.flash_freq=80m bpi_leaf_s3.menu.FlashSize.8M=8MB (64Mb) bpi_leaf_s3.menu.FlashSize.8M.build.flash_size=8MB -bpi_leaf_s3.menu.FlashSize.8M.build.partitions=default_8MB bpi_leaf_s3.menu.FlashSize.4M=4MB (32Mb) bpi_leaf_s3.menu.FlashSize.4M.build.flash_size=4MB bpi_leaf_s3.menu.FlashSize.16M=16MB (128Mb) @@ -28222,7 +28143,6 @@ frogboard.menu.FlashSize.4M=4MB (32Mb) frogboard.menu.FlashSize.4M.build.flash_size=4MB frogboard.menu.FlashSize.2M=2MB (16Mb) frogboard.menu.FlashSize.2M.build.flash_size=2MB -frogboard.menu.FlashSize.2M.build.partitions=minimal frogboard.menu.UploadSpeed.921600=921600 frogboard.menu.UploadSpeed.921600.upload.speed=921600 @@ -28819,10 +28739,8 @@ vintlabs-devkit-v1.menu.FlashSize.4M=4MB (32Mb) vintlabs-devkit-v1.menu.FlashSize.4M.build.flash_size=4MB vintlabs-devkit-v1.menu.FlashSize.8M=8MB (64Mb) vintlabs-devkit-v1.menu.FlashSize.8M.build.flash_size=8MB -vintlabs-devkit-v1.menu.FlashSize.8M.build.partitions=default_8MB vintlabs-devkit-v1.menu.FlashSize.2M=2MB (16Mb) vintlabs-devkit-v1.menu.FlashSize.2M.build.flash_size=2MB -vintlabs-devkit-v1.menu.FlashSize.2M.build.partitions=minimal vintlabs-devkit-v1.menu.FlashSize.16M=16MB (128Mb) vintlabs-devkit-v1.menu.FlashSize.16M.build.flash_size=16MB @@ -29023,10 +28941,8 @@ mgbot-iotik32a.menu.FlashSize.4M=4MB (32Mb) mgbot-iotik32a.menu.FlashSize.4M.build.flash_size=4MB mgbot-iotik32a.menu.FlashSize.8M=8MB (64Mb) mgbot-iotik32a.menu.FlashSize.8M.build.flash_size=8MB -mgbot-iotik32a.menu.FlashSize.8M.build.partitions=default_8MB mgbot-iotik32a.menu.FlashSize.2M=2MB (16Mb) mgbot-iotik32a.menu.FlashSize.2M.build.flash_size=2MB -mgbot-iotik32a.menu.FlashSize.2M.build.partitions=minimal mgbot-iotik32a.menu.FlashSize.16M=16MB (128Mb) mgbot-iotik32a.menu.FlashSize.16M.build.flash_size=16MB @@ -29172,10 +29088,8 @@ mgbot-iotik32b.menu.FlashSize.4M=4MB (32Mb) mgbot-iotik32b.menu.FlashSize.4M.build.flash_size=4MB mgbot-iotik32b.menu.FlashSize.8M=8MB (64Mb) mgbot-iotik32b.menu.FlashSize.8M.build.flash_size=8MB -mgbot-iotik32b.menu.FlashSize.8M.build.partitions=default_8MB mgbot-iotik32b.menu.FlashSize.2M=2MB (16Mb) mgbot-iotik32b.menu.FlashSize.2M.build.flash_size=2MB -mgbot-iotik32b.menu.FlashSize.2M.build.partitions=minimal mgbot-iotik32b.menu.FlashSize.16M=16MB (128Mb) mgbot-iotik32b.menu.FlashSize.16M.build.flash_size=16MB @@ -29911,10 +29825,8 @@ wifiduino32c3.menu.FlashSize.4M=4MB (32Mb) wifiduino32c3.menu.FlashSize.4M.build.flash_size=4MB wifiduino32c3.menu.FlashSize.8M=8MB (64Mb) wifiduino32c3.menu.FlashSize.8M.build.flash_size=8MB -wifiduino32c3.menu.FlashSize.8M.build.partitions=default_8MB wifiduino32c3.menu.FlashSize.2M=2MB (16Mb) wifiduino32c3.menu.FlashSize.2M.build.flash_size=2MB -wifiduino32c3.menu.FlashSize.2M.build.partitions=minimal wifiduino32c3.menu.FlashSize.16M=16MB (128Mb) wifiduino32c3.menu.FlashSize.16M.build.flash_size=16MB @@ -30032,7 +29944,6 @@ wifiduino32s3.menu.FlashSize.4M=4MB (32Mb) wifiduino32s3.menu.FlashSize.4M.build.flash_size=4MB wifiduino32s3.menu.FlashSize.8M=8MB (64Mb) wifiduino32s3.menu.FlashSize.8M.build.flash_size=8MB -wifiduino32s3.menu.FlashSize.8M.build.partitions=default_8MB wifiduino32s3.menu.FlashSize.16M=16MB (128Mb) wifiduino32s3.menu.FlashSize.16M.build.flash_size=16MB #wifiduino32s3.menu.FlashSize.32M=32MB (256Mb) @@ -31364,10 +31275,8 @@ kb32.menu.FlashSize.4M=4MB (32Mb) kb32.menu.FlashSize.4M.build.flash_size=4MB kb32.menu.FlashSize.8M=8MB (64Mb) kb32.menu.FlashSize.8M.build.flash_size=8MB -kb32.menu.FlashSize.8M.build.partitions=default_8MB kb32.menu.FlashSize.2M=2MB (16Mb) kb32.menu.FlashSize.2M.build.flash_size=2MB -kb32.menu.FlashSize.2M.build.partitions=minimal kb32.menu.FlashSize.16M=16MB (128Mb) kb32.menu.FlashSize.16M.build.flash_size=16MB @@ -31544,10 +31453,8 @@ deneyapkart.menu.FlashSize.4M=4MB (32Mb) deneyapkart.menu.FlashSize.4M.build.flash_size=4MB deneyapkart.menu.FlashSize.8M=8MB (64Mb) deneyapkart.menu.FlashSize.8M.build.flash_size=8MB -deneyapkart.menu.FlashSize.8M.build.partitions=default_8MB deneyapkart.menu.FlashSize.2M=2MB (16Mb) deneyapkart.menu.FlashSize.2M.build.flash_size=2MB -deneyapkart.menu.FlashSize.2M.build.partitions=minimal deneyapkart.menu.FlashSize.16M=16MB (128Mb) deneyapkart.menu.FlashSize.16M.build.flash_size=16MB @@ -31724,10 +31631,8 @@ deneyapkart1A.menu.FlashSize.4M=4MB (32Mb) deneyapkart1A.menu.FlashSize.4M.build.flash_size=4MB deneyapkart1A.menu.FlashSize.8M=8MB (64Mb) deneyapkart1A.menu.FlashSize.8M.build.flash_size=8MB -deneyapkart1A.menu.FlashSize.8M.build.partitions=default_8MB deneyapkart1A.menu.FlashSize.2M=2MB (16Mb) deneyapkart1A.menu.FlashSize.2M.build.flash_size=2MB -deneyapkart1A.menu.FlashSize.2M.build.partitions=minimal deneyapkart1A.menu.FlashSize.16M=16MB (128Mb) deneyapkart1A.menu.FlashSize.16M.build.flash_size=16MB @@ -31871,7 +31776,6 @@ deneyapkart1Av2.menu.FlashSize.4M=4MB (32Mb) deneyapkart1Av2.menu.FlashSize.4M.build.flash_size=4MB deneyapkart1Av2.menu.FlashSize.8M=8MB (64Mb) deneyapkart1Av2.menu.FlashSize.8M.build.flash_size=8MB -deneyapkart1Av2.menu.FlashSize.8M.build.partitions=default_8MB deneyapkart1Av2.menu.FlashSize.16M=16MB (128Mb) deneyapkart1Av2.menu.FlashSize.16M.build.flash_size=16MB #deneyapkart1Av2.menu.FlashSize.32M=32MB (256Mb) @@ -32155,10 +32059,8 @@ deneyapmini.menu.FlashSize.4M=4MB (32Mb) deneyapmini.menu.FlashSize.4M.build.flash_size=4MB deneyapmini.menu.FlashSize.8M=8MB (64Mb) deneyapmini.menu.FlashSize.8M.build.flash_size=8MB -deneyapmini.menu.FlashSize.8M.build.partitions=default_8MB deneyapmini.menu.FlashSize.2M=2MB (16Mb) deneyapmini.menu.FlashSize.2M.build.flash_size=2MB -deneyapmini.menu.FlashSize.2M.build.partitions=minimal deneyapmini.menu.FlashSize.16M=16MB (128Mb) deneyapmini.menu.FlashSize.16M.build.flash_size=16MB @@ -32347,10 +32249,8 @@ deneyapminiv2.menu.FlashSize.4M=4MB (32Mb) deneyapminiv2.menu.FlashSize.4M.build.flash_size=4MB deneyapminiv2.menu.FlashSize.8M=8MB (64Mb) deneyapminiv2.menu.FlashSize.8M.build.flash_size=8MB -deneyapminiv2.menu.FlashSize.8M.build.partitions=default_8MB deneyapminiv2.menu.FlashSize.2M=2MB (16Mb) deneyapminiv2.menu.FlashSize.2M.build.flash_size=2MB -deneyapminiv2.menu.FlashSize.2M.build.partitions=minimal deneyapminiv2.menu.FlashSize.16M=16MB (128Mb) deneyapminiv2.menu.FlashSize.16M.build.flash_size=16MB @@ -32516,10 +32416,8 @@ deneyapkartg.menu.FlashSize.4M=4MB (32Mb) deneyapkartg.menu.FlashSize.4M.build.flash_size=4MB deneyapkartg.menu.FlashSize.8M=8MB (64Mb) deneyapkartg.menu.FlashSize.8M.build.flash_size=8MB -deneyapkartg.menu.FlashSize.8M.build.partitions=default_8MB deneyapkartg.menu.FlashSize.2M=2MB (16Mb) deneyapkartg.menu.FlashSize.2M.build.flash_size=2MB -deneyapkartg.menu.FlashSize.2M.build.partitions=minimal deneyapkartg.menu.FlashSize.16M=16MB (128Mb) deneyapkartg.menu.FlashSize.16M.build.flash_size=16MB @@ -32823,10 +32721,8 @@ atmegazero_esp32s2.menu.FlashSize.4M=4MB (32Mb) atmegazero_esp32s2.menu.FlashSize.4M.build.flash_size=4MB atmegazero_esp32s2.menu.FlashSize.8M=8MB (64Mb) atmegazero_esp32s2.menu.FlashSize.8M.build.flash_size=8MB -atmegazero_esp32s2.menu.FlashSize.8M.build.partitions=default_8MB atmegazero_esp32s2.menu.FlashSize.2M=2MB (16Mb) atmegazero_esp32s2.menu.FlashSize.2M.build.flash_size=2MB -atmegazero_esp32s2.menu.FlashSize.2M.build.partitions=minimal atmegazero_esp32s2.menu.FlashSize.16M=16MB (128Mb) atmegazero_esp32s2.menu.FlashSize.16M.build.flash_size=16MB @@ -32915,7 +32811,6 @@ franzininho_wifi_esp32s2.menu.FlashSize.4M=4MB (32Mb) franzininho_wifi_esp32s2.menu.FlashSize.4M.build.flash_size=4MB franzininho_wifi_esp32s2.menu.FlashSize.8M=8MB (64Mb) franzininho_wifi_esp32s2.menu.FlashSize.8M.build.flash_size=8MB -franzininho_wifi_esp32s2.menu.FlashSize.8M.build.partitions=default_8MB franzininho_wifi_esp32s2.menu.FlashSize.16M=16MB (128Mb) franzininho_wifi_esp32s2.menu.FlashSize.16M.build.flash_size=16MB @@ -33023,7 +32918,6 @@ franzininho_wifi_msc_esp32s2.menu.FlashSize.4M=4MB (32Mb) franzininho_wifi_msc_esp32s2.menu.FlashSize.4M.build.flash_size=4MB franzininho_wifi_msc_esp32s2.menu.FlashSize.8M=8MB (64Mb) franzininho_wifi_msc_esp32s2.menu.FlashSize.8M.build.flash_size=8MB -franzininho_wifi_msc_esp32s2.menu.FlashSize.8M.build.partitions=default_8MB franzininho_wifi_msc_esp32s2.menu.FlashSize.16M=16MB (128Mb) franzininho_wifi_msc_esp32s2.menu.FlashSize.16M.build.flash_size=16MB @@ -33160,7 +33054,6 @@ tamc_termod_s3.menu.FlashSize.4M=4MB (32Mb) tamc_termod_s3.menu.FlashSize.4M.build.flash_size=4MB tamc_termod_s3.menu.FlashSize.8M=8MB (64Mb) tamc_termod_s3.menu.FlashSize.8M.build.flash_size=8MB -tamc_termod_s3.menu.FlashSize.8M.build.partitions=default_8MB tamc_termod_s3.menu.FlashSize.16M=16MB (128Mb) tamc_termod_s3.menu.FlashSize.16M.build.flash_size=16MB @@ -33622,7 +33515,6 @@ lionbit.menu.FlashFreq.40.build.flash_freq=40m lionbit.menu.FlashSize.4M=4MB (32Mb) lionbit.menu.FlashSize.4M.build.flash_size=4MB -lionbit.menu.FlashSize.4M.build.partitions=default @@ -33970,10 +33862,8 @@ XIAO_ESP32C3.menu.FlashSize.4M=4MB (32Mb) XIAO_ESP32C3.menu.FlashSize.4M.build.flash_size=4MB XIAO_ESP32C3.menu.FlashSize.8M=8MB (64Mb) XIAO_ESP32C3.menu.FlashSize.8M.build.flash_size=8MB -XIAO_ESP32C3.menu.FlashSize.8M.build.partitions=default_8MB XIAO_ESP32C3.menu.FlashSize.2M=2MB (16Mb) XIAO_ESP32C3.menu.FlashSize.2M.build.flash_size=2MB -XIAO_ESP32C3.menu.FlashSize.2M.build.partitions=minimal XIAO_ESP32C3.menu.FlashSize.16M=16MB (128Mb) XIAO_ESP32C3.menu.FlashSize.16M.build.flash_size=16MB @@ -34246,7 +34136,6 @@ XIAO_ESP32S3.menu.FlashMode.dio.build.flash_freq=80m XIAO_ESP32S3.menu.FlashSize.8M=8MB (64Mb) XIAO_ESP32S3.menu.FlashSize.8M.build.flash_size=8MB -XIAO_ESP32S3.menu.FlashSize.8M.build.partitions=default_8MB XIAO_ESP32S3.menu.LoopCore.1=Core 1 XIAO_ESP32S3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 @@ -34669,10 +34558,8 @@ department_of_alchemy_minimain_esp32s2.menu.FlashSize.4M=4MB (32Mb) department_of_alchemy_minimain_esp32s2.menu.FlashSize.4M.build.flash_size=4MB department_of_alchemy_minimain_esp32s2.menu.FlashSize.8M=8MB (64Mb) department_of_alchemy_minimain_esp32s2.menu.FlashSize.8M.build.flash_size=8MB -department_of_alchemy_minimain_esp32s2.menu.FlashSize.8M.build.partitions=default_8MB department_of_alchemy_minimain_esp32s2.menu.FlashSize.2M=2MB (16Mb) department_of_alchemy_minimain_esp32s2.menu.FlashSize.2M.build.flash_size=2MB -department_of_alchemy_minimain_esp32s2.menu.FlashSize.2M.build.partitions=minimal department_of_alchemy_minimain_esp32s2.menu.FlashSize.16M=16MB (128Mb) department_of_alchemy_minimain_esp32s2.menu.FlashSize.16M.build.flash_size=16MB @@ -36413,10 +36300,8 @@ VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.4M=4MB (32Mb) VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.4M.build.flash_size=4MB VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.8M=8MB (64Mb) VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.8M.build.flash_size=8MB -VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.8M.build.partitions=default_8MB VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.2M=2MB (16Mb) VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.2M.build.flash_size=2MB -VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.2M.build.partitions=minimal VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.16M=16MB (128Mb) VALTRACK_V4_VTS_ESP32_C3.menu.FlashSize.16M.build.flash_size=16MB @@ -36566,10 +36451,8 @@ VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.4M=4MB (32Mb) VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.4M.build.flash_size=4MB VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.8M=8MB (64Mb) VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.8M.build.flash_size=8MB -VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.8M.build.partitions=default_8MB VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.2M=2MB (16Mb) VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.2M.build.flash_size=2MB -VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.2M.build.partitions=minimal VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.16M=16MB (128Mb) VALTRACK_V4_MFW_ESP32_C3.menu.FlashSize.16M.build.flash_size=16MB @@ -36687,7 +36570,6 @@ Edgebox-ESP-100.menu.FlashSize.4M=4MB (32Mb) Edgebox-ESP-100.menu.FlashSize.4M.build.flash_size=4MB Edgebox-ESP-100.menu.FlashSize.8M=8MB (64Mb) Edgebox-ESP-100.menu.FlashSize.8M.build.flash_size=8MB -Edgebox-ESP-100.menu.FlashSize.8M.build.partitions=default_8MB Edgebox-ESP-100.menu.FlashSize.16M=16MB (128Mb) Edgebox-ESP-100.menu.FlashSize.16M.build.flash_size=16MB #Edgebox-ESP-100.menu.FlashSize.32M=32MB (256Mb) @@ -37060,7 +36942,6 @@ nebulas3.menu.FlashSize.4M=4MB (32Mb) nebulas3.menu.FlashSize.4M.build.flash_size=4MB nebulas3.menu.FlashSize.8M=8MB (64Mb) nebulas3.menu.FlashSize.8M.build.flash_size=8MB -nebulas3.menu.FlashSize.8M.build.partitions=default_8MB nebulas3.menu.FlashSize.16M=16MB (128Mb) nebulas3.menu.FlashSize.16M.build.flash_size=16MB @@ -37285,7 +37166,6 @@ lionbits3.menu.FlashSize.4M=4MB (32Mb) lionbits3.menu.FlashSize.4M.build.flash_size=4MB lionbits3.menu.FlashSize.8M=8MB (64Mb) lionbits3.menu.FlashSize.8M.build.flash_size=8MB -lionbits3.menu.FlashSize.8M.build.partitions=default_8MB lionbits3.menu.FlashSize.16M=16MB (128Mb) lionbits3.menu.FlashSize.16M.build.flash_size=16MB #lionbits3.menu.FlashSize.32M=32MB (256Mb) @@ -39314,7 +39194,6 @@ epulse_feather_c6.menu.FlashSize.4M=4MB (32Mb) epulse_feather_c6.menu.FlashSize.4M.build.flash_size=4MB epulse_feather_c6.menu.FlashSize.2M=2MB (16Mb) epulse_feather_c6.menu.FlashSize.2M.build.flash_size=2MB -epulse_feather_c6.menu.FlashSize.2M.build.partitions=minimal epulse_feather_c6.menu.UploadSpeed.921600=921600 epulse_feather_c6.menu.UploadSpeed.921600.upload.speed=921600 @@ -39457,7 +39336,6 @@ Geekble_ESP32C3.menu.FlashSize.4M=4MB (Default) Geekble_ESP32C3.menu.FlashSize.4M.build.flash_size=4MB Geekble_ESP32C3.menu.FlashSize.2M=2MB Geekble_ESP32C3.menu.FlashSize.2M.build.flash_size=2MB -Geekble_ESP32C3.menu.FlashSize.2M.build.partitions=minimal Geekble_ESP32C3.menu.UploadSpeed.921600=921600 (Default) Geekble_ESP32C3.menu.UploadSpeed.921600.upload.speed=921600 From 8ce5f775fe928dc4541b0fecaf710de58aa3d198 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:57:08 -0300 Subject: [PATCH 045/406] ci(compilation): Use default partition and add append to FQBN option (#10392) * ci(partitions): Use default partition for compilation in CI * fix(ci): Fix paths for sdkconfig * Fix build of camera web server * fix(ci): Fix test requirements check * ci(append): Add option to append to all FQBNs * fix(json): Fix JSON files to compile examples * fix(example): Use requires instead of target in ci.json fix(zigbee): Improve JSON files Co-authored-by: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> * fix(regex): Trim argument before grep * docs(ci): Add documentation about FQBNs in CI * fix(json): Remove redundant FQBNs * fix(json): Skip requirements if libs are not installed * fix(partitions): Use rainmaker specific partitions --------- Co-authored-by: me-no-dev Co-authored-by: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> --- .github/scripts/install-platformio-esp32.sh | 8 ++- .github/scripts/sketch_utils.sh | 60 ++++++++++++------- .github/scripts/tests_run.sh | 31 ++++++---- .github/workflows/tests_build.yml | 3 + .github/workflows/tests_hw.yml | 4 -- docs/en/contributing.rst | 46 +++++++++++++- .../examples/Camera/CameraWebServer/ci.json | 15 +++++ .../Camera/CameraWebServer/partitions.csv | 5 +- .../RainMaker/examples/RMakerCustom/ci.json | 3 +- .../examples/RMakerCustomAirCooler/ci.json | 3 +- .../examples/RMakerSonoffDualR3/ci.json | 3 +- .../RainMaker/examples/RMakerSwitch/ci.json | 3 +- libraries/WiFiProv/examples/WiFiProv/ci.json | 1 + .../Zigbee_Color_Dimmable_Light/ci.json | 18 ++---- .../Zigbee_Color_Dimmer_Switch/ci.json | 18 ++---- .../examples/Zigbee_On_Off_Light/ci.json | 18 ++---- .../examples/Zigbee_On_Off_Switch/ci.json | 18 ++---- .../examples/Zigbee_Scan_Networks/ci.json | 18 ++---- .../Zigbee_Temperature_Sensor/ci.json | 18 ++---- .../Zigbee/examples/Zigbee_Thermostat/ci.json | 18 ++---- platform.txt | 4 ++ 21 files changed, 168 insertions(+), 147 deletions(-) diff --git a/.github/scripts/install-platformio-esp32.sh b/.github/scripts/install-platformio-esp32.sh index 393c9f3a7d6..a9aab496e19 100755 --- a/.github/scripts/install-platformio-esp32.sh +++ b/.github/scripts/install-platformio-esp32.sh @@ -6,7 +6,7 @@ PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git" TOOLCHAIN_VERSION="12.2.0+20230208" ESPTOOLPY_VERSION="~1.40501.0" ESPRESSIF_ORGANIZATION_NAME="espressif" -LIBS_DIR="tools/esp32-arduino-libs" +SDKCONFIG_DIR="$PLATFORMIO_ESP32_PATH/tools/esp32-arduino-libs" echo "Installing Python Wheel ..." pip install wheel > /dev/null 2>&1 @@ -100,7 +100,8 @@ function count_sketches(){ # count_sketches requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then for requirement in $requirements; do - found_line=$(grep -E "^$requirement" $LIBS_DIR/esp32/sdkconfig) + requirement=$(echo $requirement | xargs) + found_line=$(grep -E "^$requirement" "$SDKCONFIG_DIR/esp32/sdkconfig") if [[ "$found_line" == "" ]]; then continue 2 fi @@ -190,7 +191,8 @@ function build_pio_sketches(){ # build_pio_sketches [extra-options] while [ ! -z "$1" ]; do @@ -83,14 +89,21 @@ function build_sketch(){ # build_sketch [ex len=1 + if [ -f $sketchdir/ci.json ]; then + fqbn_append=`jq -r '.fqbn_append' $sketchdir/ci.json` + if [ $fqbn_append == "null" ]; then + fqbn_append="" + fi + fi + # Default FQBN options if none were passed in the command line. - esp32_opts="PSRAM=enabled,PartitionScheme=huge_app,FlashMode=dio" - esp32s2_opts="PSRAM=enabled,PartitionScheme=huge_app,FlashMode=dio" - esp32s3_opts="PSRAM=opi,USBMode=default,PartitionScheme=huge_app,FlashMode=dio" - esp32c3_opts="PartitionScheme=huge_app,FlashMode=dio" - esp32c6_opts="PartitionScheme=huge_app,FlashMode=dio" - esp32h2_opts="PartitionScheme=huge_app,FlashMode=dio" + esp32_opts="PSRAM=enabled,FlashMode=dio${fqbn_append:+,$fqbn_append}" + esp32s2_opts="PSRAM=enabled,FlashMode=dio${fqbn_append:+,$fqbn_append}" + esp32s3_opts="PSRAM=opi,USBMode=default,FlashMode=dio${fqbn_append:+,$fqbn_append}" + esp32c3_opts="FlashMode=dio${fqbn_append:+,$fqbn_append}" + esp32c6_opts="FlashMode=dio${fqbn_append:+,$fqbn_append}" + esp32h2_opts="FlashMode=dio${fqbn_append:+,$fqbn_append}" # Select the common part of the FQBN based on the target. The rest will be # appended depending on the passed options. @@ -154,7 +167,8 @@ function build_sketch(){ # build_sketch [ex requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then for requirement in $requirements; do - found_line=$(grep -E "^$requirement" $LIBS_DIR/$target/sdkconfig) + requirement=$(echo $requirement | xargs) + found_line=$(grep -E "^$requirement" "$SDKCONFIG_DIR/$target/sdkconfig") if [[ "$found_line" == "" ]]; then echo "Target $target does not meet the requirement $requirement for $sketchname. Skipping." exit 0 @@ -270,10 +284,11 @@ function build_sketch(){ # build_sketch [ex unset options } -function count_sketches(){ # count_sketches [target] [file] +function count_sketches(){ # count_sketches [target] [file] [ignore-requirements] local path=$1 local target=$2 - local file=$3 + local ignore_requirements=$3 + local file=$4 if [ $# -lt 1 ]; then echo "ERROR: Illegal number of parameters" @@ -286,7 +301,7 @@ function count_sketches(){ # count_sketches [target] [file] return 0 fi - if [ -n "$file" ]; then + if [ -f "$file" ]; then local sketches=$(cat $file) else local sketches=$(find $path -name *.ino | sort) @@ -306,15 +321,18 @@ function count_sketches(){ # count_sketches [target] [file] continue fi - # Check if the sketch requires any configuration options - requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) - if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then - for requirement in $requirements; do - found_line=$(grep -E "^$requirement" $LIBS_DIR/$target/sdkconfig) - if [[ "$found_line" == "" ]]; then - continue 2 - fi - done + if [ "$ignore_requirements" != "1" ]; then + # Check if the sketch requires any configuration options + requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) + if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + for requirement in $requirements; do + requirement=$(echo $requirement | xargs) + found_line=$(grep -E "^$requirement" $SDKCONFIG_DIR/$target/sdkconfig) + if [[ "$found_line" == "" ]]; then + continue 2 + fi + done + fi fi fi echo $sketch >> sketches.txt @@ -392,7 +410,7 @@ function build_sketches(){ # build_sketches `_ - are used if this field is not specified. + are used if this field is not specified. This overrides the default FQBNs and the ``fqbn_append`` field. The ``wifi`` test suite is a good example of how to use the ``ci.json`` file: diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/ci.json b/libraries/ESP32/examples/Camera/CameraWebServer/ci.json index 7e0f3c89986..35c3056dda8 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/ci.json +++ b/libraries/ESP32/examples/Camera/CameraWebServer/ci.json @@ -1,4 +1,19 @@ { + "fqbn": { + "esp32": [ + "espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=custom,FlashMode=dio", + "espressif:esp32:esp32:PSRAM=disabled,PartitionScheme=custom,FlashMode=dio" + ], + "esp32s2": [ + "espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=custom,FlashMode=dio", + "espressif:esp32:esp32s2:PSRAM=disabled,PartitionScheme=custom,FlashMode=dio" + ], + "esp32s3": [ + "espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=custom,FlashMode=qio", + "espressif:esp32:esp32s3:PSRAM=enabled,USBMode=default,PartitionScheme=custom,FlashMode=qio", + "espressif:esp32:esp32s3:PSRAM=disabled,USBMode=default,PartitionScheme=custom,FlashMode=qio" + ] + }, "requires": [ "CONFIG_CAMERA_TASK_STACK_SIZE=[0-9]+" ] diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv b/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv index 4f76ca6d746..b9f18c465a7 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv +++ b/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv @@ -1,5 +1,6 @@ # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, -app0, app, ota_0, 0x10000, 0x3d0000, -fr, data, , 0x3e0000, 0x20000, +app0, app, ota_0, 0x10000, 0x3c0000, +fr, data, , 0x3d0000, 0x20000, +coredump, data, coredump,0x3f0000, 0x10000, diff --git a/libraries/RainMaker/examples/RMakerCustom/ci.json b/libraries/RainMaker/examples/RMakerCustom/ci.json index de4e92436d7..833a13f0860 100644 --- a/libraries/RainMaker/examples/RMakerCustom/ci.json +++ b/libraries/RainMaker/examples/RMakerCustom/ci.json @@ -1,6 +1,7 @@ { + "fqbn_append": "PartitionScheme=rainmaker_4MB", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK" + "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK=[1-9][0-9]*" ] } diff --git a/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json b/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json index de4e92436d7..833a13f0860 100644 --- a/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json +++ b/libraries/RainMaker/examples/RMakerCustomAirCooler/ci.json @@ -1,6 +1,7 @@ { + "fqbn_append": "PartitionScheme=rainmaker_4MB", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK" + "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK=[1-9][0-9]*" ] } diff --git a/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json b/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json index de4e92436d7..833a13f0860 100644 --- a/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json +++ b/libraries/RainMaker/examples/RMakerSonoffDualR3/ci.json @@ -1,6 +1,7 @@ { + "fqbn_append": "PartitionScheme=rainmaker_4MB", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK" + "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK=[1-9][0-9]*" ] } diff --git a/libraries/RainMaker/examples/RMakerSwitch/ci.json b/libraries/RainMaker/examples/RMakerSwitch/ci.json index de4e92436d7..833a13f0860 100644 --- a/libraries/RainMaker/examples/RMakerSwitch/ci.json +++ b/libraries/RainMaker/examples/RMakerSwitch/ci.json @@ -1,6 +1,7 @@ { + "fqbn_append": "PartitionScheme=rainmaker_4MB", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK" + "CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK=[1-9][0-9]*" ] } diff --git a/libraries/WiFiProv/examples/WiFiProv/ci.json b/libraries/WiFiProv/examples/WiFiProv/ci.json index 36babb82730..04eb62b977a 100644 --- a/libraries/WiFiProv/examples/WiFiProv/ci.json +++ b/libraries/WiFiProv/examples/WiFiProv/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y" ] diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json index 3aaf44eb376..7b7ccef8ed7 100644 --- a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/ci.json @@ -1,16 +1,6 @@ { - "fqbn": { - "esp32c6": [ - "espressif:esp32:esp32c6:PartitionScheme=zigbee,ZigbeeMode=ed" - ], - "esp32h2": [ - "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" - ] - }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json index c916121b991..e79a477da11 100644 --- a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/ci.json @@ -1,16 +1,6 @@ { - "fqbn": { - "esp32c6": [ - "espressif:esp32:esp32c6:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" - ], - "esp32h2": [ - "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" - ] - }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json index 3aaf44eb376..7b7ccef8ed7 100644 --- a/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Light/ci.json @@ -1,16 +1,6 @@ { - "fqbn": { - "esp32c6": [ - "espressif:esp32:esp32c6:PartitionScheme=zigbee,ZigbeeMode=ed" - ], - "esp32h2": [ - "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" - ] - }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json index c916121b991..e79a477da11 100644 --- a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/ci.json @@ -1,16 +1,6 @@ { - "fqbn": { - "esp32c6": [ - "espressif:esp32:esp32c6:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" - ], - "esp32h2": [ - "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" - ] - }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json b/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json index 3aaf44eb376..7b7ccef8ed7 100644 --- a/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Scan_Networks/ci.json @@ -1,16 +1,6 @@ { - "fqbn": { - "esp32c6": [ - "espressif:esp32:esp32c6:PartitionScheme=zigbee,ZigbeeMode=ed" - ], - "esp32h2": [ - "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" - ] - }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json index 3aaf44eb376..7b7ccef8ed7 100644 --- a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/ci.json @@ -1,16 +1,6 @@ { - "fqbn": { - "esp32c6": [ - "espressif:esp32:esp32c6:PartitionScheme=zigbee,ZigbeeMode=ed" - ], - "esp32h2": [ - "espressif:esp32:esp32h2:PartitionScheme=zigbee,ZigbeeMode=ed" - ] - }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json b/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json index c916121b991..e79a477da11 100644 --- a/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/ci.json @@ -1,16 +1,6 @@ { - "fqbn": { - "esp32c6": [ - "espressif:esp32:esp32c6:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" - ], - "esp32h2": [ - "espressif:esp32:esp32h2:PartitionScheme=zigbee_zczr,ZigbeeMode=zczr" - ] - }, - "targets": { - "esp32": false, - "esp32c3": false, - "esp32s2": false, - "esp32s3": false - } + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] } diff --git a/platform.txt b/platform.txt index 873e27b0ecb..a1574e2f776 100644 --- a/platform.txt +++ b/platform.txt @@ -143,6 +143,10 @@ recipe.hooks.prebuild.7.pattern.windows=cmd /c type nul > "{file_opts.path}" recipe.hooks.core.prebuild.1.pattern.windows=cmd /c echo "-DARDUINO_CORE_BUILD" > "{file_opts.path}" recipe.hooks.core.postbuild.1.pattern.windows=cmd /c type nul > "{file_opts.path}" +# Copy sdkconfig to build folder +recipe.hooks.prebuild.8.pattern=/usr/bin/env bash -c "cp -f "{runtime.platform.path}"/tools/esp32-arduino-libs/{build.mcu}/sdkconfig "{build.path}"/sdkconfig" +recipe.hooks.prebuild.8.pattern.windows=cmd /c COPY /y "{runtime.platform.path}\tools\esp32-arduino-libs\{build.mcu}\sdkconfig" "{build.path}\sdkconfig" + ## Compile c files recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.extra_flags} {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" -DARDUINO_VARIANT="{build.variant}" -DARDUINO_PARTITION_{build.partitions} {build.extra_flags} {compiler.cpreprocessor.flags} {includes} "@{build.opt.path}" "@{file_opts.path}" "{source_file}" -o "{object_file}" From 765173372f5e1fde9285b4180982589e4289aa9b Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:33:27 -0300 Subject: [PATCH 046/406] Add P4 to chip info --- cores/esp32/Esp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 6a6ed11e463..aa189516469 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -300,6 +300,7 @@ const char *EspClass::getChipModel(void) { case CHIP_ESP32C2: return "ESP32-C2"; case CHIP_ESP32C6: return "ESP32-C6"; case CHIP_ESP32H2: return "ESP32-H2"; + case CHIP_ESP32P4: return "ESP32-P4"; default: return "UNKNOWN"; } #endif From 630377f7d3f8c859698529e4e1448d4551a9fa67 Mon Sep 17 00:00:00 2001 From: Bharat Pi <133974527+Bharat-Pi@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:13:51 +0530 Subject: [PATCH 047/406] =?UTF-8?q?feat(Variants):=20Add=20Arduino=20libra?= =?UTF-8?q?ries=20for=20Lora=204G=20Module=20and=20Node=20Wifi=20o?= =?UTF-8?q?=E2=80=A6=20(#10402)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(esp32): Added support for BharatPi 4G, LoRa & NodeWifi Boards * fix(variant): Fixed review comments for SPI and I2C Pins * fix(variant): Fixed review comments and Lora build fix * fix(variant): Fixed review comments for board name * fix(review): Fixed review comment for CI * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- boards.txt | 473 +++++++++++++++++++++ variants/BharatPi-A7672S-4G/pins_arduino.h | 31 ++ variants/BharatPi-LoRa/pins_arduino.h | 35 ++ variants/BharatPi-Node-Wifi/pins_arduino.h | 35 ++ 4 files changed, 574 insertions(+) create mode 100644 variants/BharatPi-A7672S-4G/pins_arduino.h create mode 100644 variants/BharatPi-LoRa/pins_arduino.h create mode 100644 variants/BharatPi-Node-Wifi/pins_arduino.h diff --git a/boards.txt b/boards.txt index c73d81b6f31..971f99a0cbc 100644 --- a/boards.txt +++ b/boards.txt @@ -2780,6 +2780,479 @@ aventen_s3_sync.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +BharatPi-Node-Wifi.name=BharatPi Node Wifi Module + +BharatPi-Node-Wifi.bootloader.tool=esptool_py +BharatPi-Node-Wifi.bootloader.tool.default=esptool_py + +BharatPi-Node-Wifi.upload.tool=esptool_py +BharatPi-Node-Wifi.upload.tool.default=esptool_py +BharatPi-Node-Wifi.upload.tool.network=esp_ota + +BharatPi-Node-Wifi.upload.maximum_size=1310720 +BharatPi-Node-Wifi.upload.maximum_data_size=327680 +BharatPi-Node-Wifi.upload.flags= +BharatPi-Node-Wifi.upload.extra_flags= + +BharatPi-Node-Wifi.serial.disableDTR=true +BharatPi-Node-Wifi.serial.disableRTS=true + +BharatPi-Node-Wifi.build.tarch=xtensa +BharatPi-Node-Wifi.build.bootloader_addr=0x1000 +BharatPi-Node-Wifi.build.target=esp32 +BharatPi-Node-Wifi.build.mcu=esp32 +BharatPi-Node-Wifi.build.core=esp32 +BharatPi-Node-Wifi.build.variant=BharatPi-Node-Wifi +BharatPi-Node-Wifi.build.board=BHARATPI_NODE_WIFI + +BharatPi-Node-Wifi.build.f_cpu=240000000L +BharatPi-Node-Wifi.build.flash_size=4MB +BharatPi-Node-Wifi.build.flash_freq=40m +BharatPi-Node-Wifi.build.flash_mode=dio +BharatPi-Node-Wifi.build.boot=dio +BharatPi-Node-Wifi.build.partitions=default +BharatPi-Node-Wifi.build.defines= +BharatPi-Node-Wifi.build.loop_core= +BharatPi-Node-Wifi.build.event_core= + +BharatPi-Node-Wifi.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +BharatPi-Node-Wifi.menu.PartitionScheme.default.build.partitions=default +BharatPi-Node-Wifi.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +BharatPi-Node-Wifi.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +BharatPi-Node-Wifi.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +BharatPi-Node-Wifi.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +BharatPi-Node-Wifi.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +BharatPi-Node-Wifi.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +BharatPi-Node-Wifi.menu.PartitionScheme.minimal.build.partitions=minimal +BharatPi-Node-Wifi.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +BharatPi-Node-Wifi.menu.PartitionScheme.no_ota.build.partitions=no_ota +BharatPi-Node-Wifi.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +BharatPi-Node-Wifi.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +BharatPi-Node-Wifi.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +BharatPi-Node-Wifi.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +BharatPi-Node-Wifi.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +BharatPi-Node-Wifi.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +BharatPi-Node-Wifi.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +BharatPi-Node-Wifi.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +BharatPi-Node-Wifi.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +BharatPi-Node-Wifi.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +BharatPi-Node-Wifi.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +BharatPi-Node-Wifi.menu.PartitionScheme.huge_app.build.partitions=huge_app +BharatPi-Node-Wifi.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +BharatPi-Node-Wifi.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +BharatPi-Node-Wifi.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +BharatPi-Node-Wifi.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +BharatPi-Node-Wifi.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +BharatPi-Node-Wifi.menu.PartitionScheme.fatflash.build.partitions=ffat +BharatPi-Node-Wifi.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +BharatPi-Node-Wifi.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +BharatPi-Node-Wifi.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +BharatPi-Node-Wifi.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +BharatPi-Node-Wifi.menu.PartitionScheme.rainmaker=RainMaker +BharatPi-Node-Wifi.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +BharatPi-Node-Wifi.menu.PartitionScheme.rainmaker.upload.maximum_size=3145728 +BharatPi-Node-Wifi.menu.PartitionScheme.custom=Custom +BharatPi-Node-Wifi.menu.PartitionScheme.custom.build.partitions= +BharatPi-Node-Wifi.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +BharatPi-Node-Wifi.menu.CPUFreq.240=240MHz (WiFi/BT) +BharatPi-Node-Wifi.menu.CPUFreq.240.build.f_cpu=240000000L +BharatPi-Node-Wifi.menu.CPUFreq.160=160MHz (WiFi/BT) +BharatPi-Node-Wifi.menu.CPUFreq.160.build.f_cpu=160000000L +BharatPi-Node-Wifi.menu.CPUFreq.80=80MHz (WiFi/BT) +BharatPi-Node-Wifi.menu.CPUFreq.80.build.f_cpu=80000000L +BharatPi-Node-Wifi.menu.CPUFreq.40=40MHz (40MHz XTAL) +BharatPi-Node-Wifi.menu.CPUFreq.40.build.f_cpu=40000000L +BharatPi-Node-Wifi.menu.CPUFreq.26=26MHz (26MHz XTAL) +BharatPi-Node-Wifi.menu.CPUFreq.26.build.f_cpu=26000000L +BharatPi-Node-Wifi.menu.CPUFreq.20=20MHz (40MHz XTAL) +BharatPi-Node-Wifi.menu.CPUFreq.20.build.f_cpu=20000000L +BharatPi-Node-Wifi.menu.CPUFreq.13=13MHz (26MHz XTAL) +BharatPi-Node-Wifi.menu.CPUFreq.13.build.f_cpu=13000000L +BharatPi-Node-Wifi.menu.CPUFreq.10=10MHz (40MHz XTAL) +BharatPi-Node-Wifi.menu.CPUFreq.10.build.f_cpu=10000000L + +BharatPi-Node-Wifi.menu.FlashMode.qio=QIO +BharatPi-Node-Wifi.menu.FlashMode.qio.build.flash_mode=dio +BharatPi-Node-Wifi.menu.FlashMode.qio.build.boot=qio +BharatPi-Node-Wifi.menu.FlashMode.dio=DIO +BharatPi-Node-Wifi.menu.FlashMode.dio.build.flash_mode=dio +BharatPi-Node-Wifi.menu.FlashMode.dio.build.boot=dio + +BharatPi-Node-Wifi.menu.FlashFreq.80=80MHz +BharatPi-Node-Wifi.menu.FlashFreq.80.build.flash_freq=80m +BharatPi-Node-Wifi.menu.FlashFreq.40=40MHz +BharatPi-Node-Wifi.menu.FlashFreq.40.build.flash_freq=40m + +BharatPi-Node-Wifi.menu.FlashSize.4M=4MB (32Mb) +BharatPi-Node-Wifi.menu.FlashSize.4M.build.flash_size=4MB +BharatPi-Node-Wifi.menu.FlashSize.8M=8MB (64Mb) +BharatPi-Node-Wifi.menu.FlashSize.8M.build.flash_size=8MB +BharatPi-Node-Wifi.menu.FlashSize.8M.build.partitions=default_8MB +BharatPi-Node-Wifi.menu.FlashSize.16M=16MB (128Mb) +BharatPi-Node-Wifi.menu.FlashSize.16M.build.flash_size=16MB + +BharatPi-Node-Wifi.menu.UploadSpeed.921600=921600 +BharatPi-Node-Wifi.menu.UploadSpeed.921600.upload.speed=921600 +BharatPi-Node-Wifi.menu.UploadSpeed.115200=115200 +BharatPi-Node-Wifi.menu.UploadSpeed.115200.upload.speed=115200 +BharatPi-Node-Wifi.menu.UploadSpeed.256000.windows=256000 +BharatPi-Node-Wifi.menu.UploadSpeed.256000.upload.speed=256000 +BharatPi-Node-Wifi.menu.UploadSpeed.230400.windows.upload.speed=256000 +BharatPi-Node-Wifi.menu.UploadSpeed.230400=230400 +BharatPi-Node-Wifi.menu.UploadSpeed.230400.upload.speed=230400 +BharatPi-Node-Wifi.menu.UploadSpeed.460800.linux=460800 +BharatPi-Node-Wifi.menu.UploadSpeed.460800.macosx=460800 +BharatPi-Node-Wifi.menu.UploadSpeed.460800.upload.speed=460800 +BharatPi-Node-Wifi.menu.UploadSpeed.512000.windows=512000 +BharatPi-Node-Wifi.menu.UploadSpeed.512000.upload.speed=512000 + +BharatPi-Node-Wifi.menu.LoopCore.1=Core 1 +BharatPi-Node-Wifi.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +BharatPi-Node-Wifi.menu.LoopCore.0=Core 0 +BharatPi-Node-Wifi.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +BharatPi-Node-Wifi.menu.EventsCore.1=Core 1 +BharatPi-Node-Wifi.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +BharatPi-Node-Wifi.menu.EventsCore.0=Core 0 +BharatPi-Node-Wifi.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +BharatPi-Node-Wifi.menu.DebugLevel.none=None +BharatPi-Node-Wifi.menu.DebugLevel.none.build.code_debug=0 +BharatPi-Node-Wifi.menu.DebugLevel.error=Error +BharatPi-Node-Wifi.menu.DebugLevel.error.build.code_debug=1 +BharatPi-Node-Wifi.menu.DebugLevel.warn=Warn +BharatPi-Node-Wifi.menu.DebugLevel.warn.build.code_debug=2 +BharatPi-Node-Wifi.menu.DebugLevel.info=Info +BharatPi-Node-Wifi.menu.DebugLevel.info.build.code_debug=3 +BharatPi-Node-Wifi.menu.DebugLevel.debug=Debug +BharatPi-Node-Wifi.menu.DebugLevel.debug.build.code_debug=4 +BharatPi-Node-Wifi.menu.DebugLevel.verbose=Verbose +BharatPi-Node-Wifi.menu.DebugLevel.verbose.build.code_debug=5 + +BharatPi-Node-Wifi.menu.EraseFlash.none=Disabled +BharatPi-Node-Wifi.menu.EraseFlash.none.upload.erase_cmd= +BharatPi-Node-Wifi.menu.EraseFlash.all=Enabled +BharatPi-Node-Wifi.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + + +BharatPi-A7672S-4G.name=BharatPi A7672S 4G Module + +BharatPi-A7672S-4G.bootloader.tool=esptool_py +BharatPi-A7672S-4G.bootloader.tool.default=esptool_py + +BharatPi-A7672S-4G.upload.tool=esptool_py +BharatPi-A7672S-4G.upload.tool.default=esptool_py +BharatPi-A7672S-4G.upload.tool.network=esp_ota + +BharatPi-A7672S-4G.upload.maximum_size=1310720 +BharatPi-A7672S-4G.upload.maximum_data_size=327680 +BharatPi-A7672S-4G.upload.flags= +BharatPi-A7672S-4G.upload.extra_flags= + +BharatPi-A7672S-4G.serial.disableDTR=true +BharatPi-A7672S-4G.serial.disableRTS=true + +BharatPi-A7672S-4G.build.tarch=xtensa +BharatPi-A7672S-4G.build.bootloader_addr=0x1000 +BharatPi-A7672S-4G.build.target=esp32 +BharatPi-A7672S-4G.build.mcu=esp32 +BharatPi-A7672S-4G.build.core=esp32 +BharatPi-A7672S-4G.build.variant=BharatPi-A7672S-4G +BharatPi-A7672S-4G.build.board=BHARATPI_A7672S_4G + +BharatPi-A7672S-4G.build.f_cpu=240000000L +BharatPi-A7672S-4G.build.flash_size=4MB +BharatPi-A7672S-4G.build.flash_freq=40m +BharatPi-A7672S-4G.build.flash_mode=dio +BharatPi-A7672S-4G.build.boot=dio +BharatPi-A7672S-4G.build.partitions=default +BharatPi-A7672S-4G.build.defines= +BharatPi-A7672S-4G.build.loop_core= +BharatPi-A7672S-4G.build.event_core= + +BharatPi-A7672S-4G.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +BharatPi-A7672S-4G.menu.PartitionScheme.default.build.partitions=default +BharatPi-A7672S-4G.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +BharatPi-A7672S-4G.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +BharatPi-A7672S-4G.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +BharatPi-A7672S-4G.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +BharatPi-A7672S-4G.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +BharatPi-A7672S-4G.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +BharatPi-A7672S-4G.menu.PartitionScheme.minimal.build.partitions=minimal +BharatPi-A7672S-4G.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +BharatPi-A7672S-4G.menu.PartitionScheme.no_ota.build.partitions=no_ota +BharatPi-A7672S-4G.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +BharatPi-A7672S-4G.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +BharatPi-A7672S-4G.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +BharatPi-A7672S-4G.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +BharatPi-A7672S-4G.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +BharatPi-A7672S-4G.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +BharatPi-A7672S-4G.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +BharatPi-A7672S-4G.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +BharatPi-A7672S-4G.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +BharatPi-A7672S-4G.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +BharatPi-A7672S-4G.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +BharatPi-A7672S-4G.menu.PartitionScheme.huge_app.build.partitions=huge_app +BharatPi-A7672S-4G.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +BharatPi-A7672S-4G.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +BharatPi-A7672S-4G.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +BharatPi-A7672S-4G.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +BharatPi-A7672S-4G.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +BharatPi-A7672S-4G.menu.PartitionScheme.fatflash.build.partitions=ffat +BharatPi-A7672S-4G.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +BharatPi-A7672S-4G.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +BharatPi-A7672S-4G.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +BharatPi-A7672S-4G.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +BharatPi-A7672S-4G.menu.PartitionScheme.rainmaker=RainMaker +BharatPi-A7672S-4G.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +BharatPi-A7672S-4G.menu.PartitionScheme.rainmaker.upload.maximum_size=3145728 +BharatPi-A7672S-4G.menu.PartitionScheme.custom=Custom +BharatPi-A7672S-4G.menu.PartitionScheme.custom.build.partitions= +BharatPi-A7672S-4G.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +BharatPi-A7672S-4G.menu.CPUFreq.240=240MHz (WiFi/BT) +BharatPi-A7672S-4G.menu.CPUFreq.240.build.f_cpu=240000000L +BharatPi-A7672S-4G.menu.CPUFreq.160=160MHz (WiFi/BT) +BharatPi-A7672S-4G.menu.CPUFreq.160.build.f_cpu=160000000L +BharatPi-A7672S-4G.menu.CPUFreq.80=80MHz (WiFi/BT) +BharatPi-A7672S-4G.menu.CPUFreq.80.build.f_cpu=80000000L +BharatPi-A7672S-4G.menu.CPUFreq.40=40MHz (40MHz XTAL) +BharatPi-A7672S-4G.menu.CPUFreq.40.build.f_cpu=40000000L +BharatPi-A7672S-4G.menu.CPUFreq.26=26MHz (26MHz XTAL) +BharatPi-A7672S-4G.menu.CPUFreq.26.build.f_cpu=26000000L +BharatPi-A7672S-4G.menu.CPUFreq.20=20MHz (40MHz XTAL) +BharatPi-A7672S-4G.menu.CPUFreq.20.build.f_cpu=20000000L +BharatPi-A7672S-4G.menu.CPUFreq.13=13MHz (26MHz XTAL) +BharatPi-A7672S-4G.menu.CPUFreq.13.build.f_cpu=13000000L +BharatPi-A7672S-4G.menu.CPUFreq.10=10MHz (40MHz XTAL) +BharatPi-A7672S-4G.menu.CPUFreq.10.build.f_cpu=10000000L + +BharatPi-A7672S-4G.menu.FlashMode.qio=QIO +BharatPi-A7672S-4G.menu.FlashMode.qio.build.flash_mode=dio +BharatPi-A7672S-4G.menu.FlashMode.qio.build.boot=qio +BharatPi-A7672S-4G.menu.FlashMode.dio=DIO +BharatPi-A7672S-4G.menu.FlashMode.dio.build.flash_mode=dio +BharatPi-A7672S-4G.menu.FlashMode.dio.build.boot=dio + +BharatPi-A7672S-4G.menu.FlashFreq.80=80MHz +BharatPi-A7672S-4G.menu.FlashFreq.80.build.flash_freq=80m +BharatPi-A7672S-4G.menu.FlashFreq.40=40MHz +BharatPi-A7672S-4G.menu.FlashFreq.40.build.flash_freq=40m + +BharatPi-A7672S-4G.menu.FlashSize.4M=4MB (32Mb) +BharatPi-A7672S-4G.menu.FlashSize.4M.build.flash_size=4MB +BharatPi-A7672S-4G.menu.FlashSize.8M=8MB (64Mb) +BharatPi-A7672S-4G.menu.FlashSize.8M.build.flash_size=8MB +BharatPi-A7672S-4G.menu.FlashSize.8M.build.partitions=default_8MB +BharatPi-A7672S-4G.menu.FlashSize.16M=16MB (128Mb) +BharatPi-A7672S-4G.menu.FlashSize.16M.build.flash_size=16MB + +BharatPi-A7672S-4G.menu.UploadSpeed.921600=921600 +BharatPi-A7672S-4G.menu.UploadSpeed.921600.upload.speed=921600 +BharatPi-A7672S-4G.menu.UploadSpeed.115200=115200 +BharatPi-A7672S-4G.menu.UploadSpeed.115200.upload.speed=115200 +BharatPi-A7672S-4G.menu.UploadSpeed.256000.windows=256000 +BharatPi-A7672S-4G.menu.UploadSpeed.256000.upload.speed=256000 +BharatPi-A7672S-4G.menu.UploadSpeed.230400.windows.upload.speed=256000 +BharatPi-A7672S-4G.menu.UploadSpeed.230400=230400 +BharatPi-A7672S-4G.menu.UploadSpeed.230400.upload.speed=230400 +BharatPi-A7672S-4G.menu.UploadSpeed.460800.linux=460800 +BharatPi-A7672S-4G.menu.UploadSpeed.460800.macosx=460800 +BharatPi-A7672S-4G.menu.UploadSpeed.460800.upload.speed=460800 +BharatPi-A7672S-4G.menu.UploadSpeed.512000.windows=512000 +BharatPi-A7672S-4G.menu.UploadSpeed.512000.upload.speed=512000 + +BharatPi-A7672S-4G.menu.LoopCore.1=Core 1 +BharatPi-A7672S-4G.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +BharatPi-A7672S-4G.menu.LoopCore.0=Core 0 +BharatPi-A7672S-4G.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +BharatPi-A7672S-4G.menu.EventsCore.1=Core 1 +BharatPi-A7672S-4G.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +BharatPi-A7672S-4G.menu.EventsCore.0=Core 0 +BharatPi-A7672S-4G.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +BharatPi-A7672S-4G.menu.DebugLevel.none=None +BharatPi-A7672S-4G.menu.DebugLevel.none.build.code_debug=0 +BharatPi-A7672S-4G.menu.DebugLevel.error=Error +BharatPi-A7672S-4G.menu.DebugLevel.error.build.code_debug=1 +BharatPi-A7672S-4G.menu.DebugLevel.warn=Warn +BharatPi-A7672S-4G.menu.DebugLevel.warn.build.code_debug=2 +BharatPi-A7672S-4G.menu.DebugLevel.info=Info +BharatPi-A7672S-4G.menu.DebugLevel.info.build.code_debug=3 +BharatPi-A7672S-4G.menu.DebugLevel.debug=Debug +BharatPi-A7672S-4G.menu.DebugLevel.debug.build.code_debug=4 +BharatPi-A7672S-4G.menu.DebugLevel.verbose=Verbose +BharatPi-A7672S-4G.menu.DebugLevel.verbose.build.code_debug=5 + +BharatPi-A7672S-4G.menu.EraseFlash.none=Disabled +BharatPi-A7672S-4G.menu.EraseFlash.none.upload.erase_cmd= +BharatPi-A7672S-4G.menu.EraseFlash.all=Enabled +BharatPi-A7672S-4G.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + + +BharatPi-LoRa.name=BharatPi LoRa Module + +BharatPi-LoRa.bootloader.tool=esptool_py +BharatPi-LoRa.bootloader.tool.default=esptool_py + +BharatPi-LoRa.upload.tool=esptool_py +BharatPi-LoRa.upload.tool.default=esptool_py +BharatPi-LoRa.upload.tool.network=esp_ota + +BharatPi-LoRa.upload.maximum_size=1310720 +BharatPi-LoRa.upload.maximum_data_size=327680 +BharatPi-LoRa.upload.flags= +BharatPi-LoRa.upload.extra_flags= + +BharatPi-LoRa.serial.disableDTR=true +BharatPi-LoRa.serial.disableRTS=true + +BharatPi-LoRa.build.tarch=xtensa +BharatPi-LoRa.build.bootloader_addr=0x1000 +BharatPi-LoRa.build.target=esp32 +BharatPi-LoRa.build.mcu=esp32 +BharatPi-LoRa.build.core=esp32 +BharatPi-LoRa.build.variant=BharatPi-LoRa +BharatPi-LoRa.build.board=BHARATPI_LORA + +BharatPi-LoRa.build.f_cpu=240000000L +BharatPi-LoRa.build.flash_size=4MB +BharatPi-LoRa.build.flash_freq=40m +BharatPi-LoRa.build.flash_mode=dio +BharatPi-LoRa.build.boot=dio +BharatPi-LoRa.build.partitions=default +BharatPi-LoRa.build.defines= +BharatPi-LoRa.build.loop_core= +BharatPi-LoRa.build.event_core= + +BharatPi-LoRa.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +BharatPi-LoRa.menu.PartitionScheme.default.build.partitions=default +BharatPi-LoRa.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +BharatPi-LoRa.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +BharatPi-LoRa.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +BharatPi-LoRa.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +BharatPi-LoRa.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +BharatPi-LoRa.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +BharatPi-LoRa.menu.PartitionScheme.minimal.build.partitions=minimal +BharatPi-LoRa.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +BharatPi-LoRa.menu.PartitionScheme.no_ota.build.partitions=no_ota +BharatPi-LoRa.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +BharatPi-LoRa.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +BharatPi-LoRa.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +BharatPi-LoRa.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +BharatPi-LoRa.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +BharatPi-LoRa.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +BharatPi-LoRa.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +BharatPi-LoRa.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +BharatPi-LoRa.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +BharatPi-LoRa.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +BharatPi-LoRa.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +BharatPi-LoRa.menu.PartitionScheme.huge_app.build.partitions=huge_app +BharatPi-LoRa.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +BharatPi-LoRa.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +BharatPi-LoRa.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +BharatPi-LoRa.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +BharatPi-LoRa.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +BharatPi-LoRa.menu.PartitionScheme.fatflash.build.partitions=ffat +BharatPi-LoRa.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +BharatPi-LoRa.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +BharatPi-LoRa.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +BharatPi-LoRa.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +BharatPi-LoRa.menu.PartitionScheme.rainmaker=RainMaker +BharatPi-LoRa.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +BharatPi-LoRa.menu.PartitionScheme.rainmaker.upload.maximum_size=3145728 +BharatPi-LoRa.menu.PartitionScheme.custom=Custom +BharatPi-LoRa.menu.PartitionScheme.custom.build.partitions= +BharatPi-LoRa.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +BharatPi-LoRa.menu.CPUFreq.240=240MHz (WiFi/BT) +BharatPi-LoRa.menu.CPUFreq.240.build.f_cpu=240000000L +BharatPi-LoRa.menu.CPUFreq.160=160MHz (WiFi/BT) +BharatPi-LoRa.menu.CPUFreq.160.build.f_cpu=160000000L +BharatPi-LoRa.menu.CPUFreq.80=80MHz (WiFi/BT) +BharatPi-LoRa.menu.CPUFreq.80.build.f_cpu=80000000L +BharatPi-LoRa.menu.CPUFreq.40=40MHz (40MHz XTAL) +BharatPi-LoRa.menu.CPUFreq.40.build.f_cpu=40000000L +BharatPi-LoRa.menu.CPUFreq.26=26MHz (26MHz XTAL) +BharatPi-LoRa.menu.CPUFreq.26.build.f_cpu=26000000L +BharatPi-LoRa.menu.CPUFreq.20=20MHz (40MHz XTAL) +BharatPi-LoRa.menu.CPUFreq.20.build.f_cpu=20000000L +BharatPi-LoRa.menu.CPUFreq.13=13MHz (26MHz XTAL) +BharatPi-LoRa.menu.CPUFreq.13.build.f_cpu=13000000L +BharatPi-LoRa.menu.CPUFreq.10=10MHz (40MHz XTAL) +BharatPi-LoRa.menu.CPUFreq.10.build.f_cpu=10000000L + +BharatPi-LoRa.menu.FlashMode.qio=QIO +BharatPi-LoRa.menu.FlashMode.qio.build.flash_mode=dio +BharatPi-LoRa.menu.FlashMode.qio.build.boot=qio +BharatPi-LoRa.menu.FlashMode.dio=DIO +BharatPi-LoRa.menu.FlashMode.dio.build.flash_mode=dio +BharatPi-LoRa.menu.FlashMode.dio.build.boot=dio + +BharatPi-LoRa.menu.FlashFreq.80=80MHz +BharatPi-LoRa.menu.FlashFreq.80.build.flash_freq=80m +BharatPi-LoRa.menu.FlashFreq.40=40MHz +BharatPi-LoRa.menu.FlashFreq.40.build.flash_freq=40m + +BharatPi-LoRa.menu.FlashSize.4M=4MB (32Mb) +BharatPi-LoRa.menu.FlashSize.4M.build.flash_size=4MB +BharatPi-LoRa.menu.FlashSize.8M=8MB (64Mb) +BharatPi-LoRa.menu.FlashSize.8M.build.flash_size=8MB +BharatPi-LoRa.menu.FlashSize.8M.build.partitions=default_8MB +BharatPi-LoRa.menu.FlashSize.16M=16MB (128Mb) +BharatPi-LoRa.menu.FlashSize.16M.build.flash_size=16MB + +BharatPi-LoRa.menu.UploadSpeed.921600=921600 +BharatPi-LoRa.menu.UploadSpeed.921600.upload.speed=921600 +BharatPi-LoRa.menu.UploadSpeed.115200=115200 +BharatPi-LoRa.menu.UploadSpeed.115200.upload.speed=115200 +BharatPi-LoRa.menu.UploadSpeed.256000.windows=256000 +BharatPi-LoRa.menu.UploadSpeed.256000.upload.speed=256000 +BharatPi-LoRa.menu.UploadSpeed.230400.windows.upload.speed=256000 +BharatPi-LoRa.menu.UploadSpeed.230400=230400 +BharatPi-LoRa.menu.UploadSpeed.230400.upload.speed=230400 +BharatPi-LoRa.menu.UploadSpeed.460800.linux=460800 +BharatPi-LoRa.menu.UploadSpeed.460800.macosx=460800 +BharatPi-LoRa.menu.UploadSpeed.460800.upload.speed=460800 +BharatPi-LoRa.menu.UploadSpeed.512000.windows=512000 +BharatPi-LoRa.menu.UploadSpeed.512000.upload.speed=512000 + +BharatPi-LoRa.menu.LoopCore.1=Core 1 +BharatPi-LoRa.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +BharatPi-LoRa.menu.LoopCore.0=Core 0 +BharatPi-LoRa.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +BharatPi-LoRa.menu.EventsCore.1=Core 1 +BharatPi-LoRa.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +BharatPi-LoRa.menu.EventsCore.0=Core 0 +BharatPi-LoRa.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +BharatPi-LoRa.menu.DebugLevel.none=None +BharatPi-LoRa.menu.DebugLevel.none.build.code_debug=0 +BharatPi-LoRa.menu.DebugLevel.error=Error +BharatPi-LoRa.menu.DebugLevel.error.build.code_debug=1 +BharatPi-LoRa.menu.DebugLevel.warn=Warn +BharatPi-LoRa.menu.DebugLevel.warn.build.code_debug=2 +BharatPi-LoRa.menu.DebugLevel.info=Info +BharatPi-LoRa.menu.DebugLevel.info.build.code_debug=3 +BharatPi-LoRa.menu.DebugLevel.debug=Debug +BharatPi-LoRa.menu.DebugLevel.debug.build.code_debug=4 +BharatPi-LoRa.menu.DebugLevel.verbose=Verbose +BharatPi-LoRa.menu.DebugLevel.verbose.build.code_debug=5 + +BharatPi-LoRa.menu.EraseFlash.none=Disabled +BharatPi-LoRa.menu.EraseFlash.none.upload.erase_cmd= +BharatPi-LoRa.menu.EraseFlash.all=Enabled +BharatPi-LoRa.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + um_bling.name=UM BLING um_bling.vid.0=0x303a um_bling.pid.0=0x817F diff --git a/variants/BharatPi-A7672S-4G/pins_arduino.h b/variants/BharatPi-A7672S-4G/pins_arduino.h new file mode 100644 index 00000000000..bf1fab09ddc --- /dev/null +++ b/variants/BharatPi-A7672S-4G/pins_arduino.h @@ -0,0 +1,31 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +static const uint8_t LED_BUILTIN = 2; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN + +static const uint8_t A0 = 14; +static const uint8_t A1 = 13; +static const uint8_t A2 = 12; +static const uint8_t A3 = 4; +static const uint8_t A4 = 2; +static const uint8_t A5 = 0; + +static const uint8_t TX = 1; +static const uint8_t RX = 3; + +static const uint8_t TX_4G = 17; +static const uint8_t RX_4G = 16; + +static const uint8_t SDA = 21; +static const uint8_t SCL = 22; + +static const uint8_t SS = 5; +static const uint8_t MOSI = 23; +static const uint8_t MISO = 19; +static const uint8_t SCK = 18; + +#endif /* Pins_Arduino_h */ diff --git a/variants/BharatPi-LoRa/pins_arduino.h b/variants/BharatPi-LoRa/pins_arduino.h new file mode 100644 index 00000000000..a42e5834a3a --- /dev/null +++ b/variants/BharatPi-LoRa/pins_arduino.h @@ -0,0 +1,35 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +static const uint8_t LED_BUILTIN = 2; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN + +static const uint8_t A0 = 14; +static const uint8_t A1 = 13; +static const uint8_t A2 = 12; +static const uint8_t A3 = 4; +static const uint8_t A4 = 2; +static const uint8_t A5 = 0; + +static const uint8_t TX = 1; +static const uint8_t RX = 3; + +static const uint8_t TX2 = 17; +static const uint8_t RX2 = 16; + +static const uint8_t LORA_SS = 4; +static const uint8_t RST = 14; +static const uint8_t DIO0 = 2; + +static const uint8_t SDA = 21; +static const uint8_t SCL = 22; + +static const uint8_t SS = 5; +static const uint8_t MOSI = 23; +static const uint8_t MISO = 19; +static const uint8_t SCK = 18; + +#endif /* Pins_Arduino_h */ diff --git a/variants/BharatPi-Node-Wifi/pins_arduino.h b/variants/BharatPi-Node-Wifi/pins_arduino.h new file mode 100644 index 00000000000..3b151289f44 --- /dev/null +++ b/variants/BharatPi-Node-Wifi/pins_arduino.h @@ -0,0 +1,35 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +static const uint8_t LED_BUILTIN = 2; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN + +static const uint8_t SAFFRON_LED = 12; +static const uint8_t WHITE_LED = 2; +static const uint8_t GREEN_LED = 13; + +static const uint8_t A0 = 14; +static const uint8_t A1 = 13; +static const uint8_t A2 = 12; +static const uint8_t A3 = 4; +static const uint8_t A4 = 2; +static const uint8_t A5 = 0; + +static const uint8_t TX = 1; +static const uint8_t RX = 3; + +static const uint8_t TX2 = 17; +static const uint8_t RX2 = 16; + +static const uint8_t SDA = 21; +static const uint8_t SCL = 22; + +static const uint8_t SS = 5; +static const uint8_t MOSI = 23; +static const uint8_t MISO = 19; +static const uint8_t SCK = 18; + +#endif /* Pins_Arduino_h */ From 4d1c9bcfa33533946622a9359391150478f38290 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 7 Oct 2024 09:54:04 -0300 Subject: [PATCH 048/406] Fix partitions for examples --- libraries/BLE/examples/BLE5_extended_scan/ci.json | 1 + libraries/BLE/examples/BLE5_multi_advertising/ci.json | 1 + libraries/BLE/examples/BLE5_periodic_advertising/ci.json | 1 + libraries/BLE/examples/BLE5_periodic_sync/ci.json | 1 + libraries/BLE/examples/Beacon_Scanner/ci.json | 1 + libraries/BLE/examples/Client/ci.json | 1 + libraries/BLE/examples/EddystoneTLM_Beacon/ci.json | 1 + libraries/BLE/examples/EddystoneURL_Beacon/ci.json | 1 + libraries/BLE/examples/Notify/ci.json | 1 + libraries/BLE/examples/Scan/ci.json | 1 + libraries/BLE/examples/Server/ci.json | 1 + libraries/BLE/examples/Server_multiconnect/ci.json | 1 + libraries/BLE/examples/UART/ci.json | 1 + libraries/BLE/examples/Write/ci.json | 1 + libraries/BLE/examples/iBeacon/ci.json | 1 + libraries/BluetoothSerial/examples/DiscoverConnect/ci.json | 1 + libraries/BluetoothSerial/examples/GetLocalMAC/ci.json | 1 + libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json | 1 + libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json | 1 + .../BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json | 1 + libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json | 1 + .../BluetoothSerial/examples/bt_classic_device_discovery/ci.json | 1 + .../BluetoothSerial/examples/bt_remove_paired_devices/ci.json | 1 + libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json | 1 + libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json | 1 + libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json | 1 + .../examples/WiFiClientSecureEnterprise/ci.json | 1 + 27 files changed, 27 insertions(+) diff --git a/libraries/BLE/examples/BLE5_extended_scan/ci.json b/libraries/BLE/examples/BLE5_extended_scan/ci.json index 9f7646a74a6..184cc25a2b0 100644 --- a/libraries/BLE/examples/BLE5_extended_scan/ci.json +++ b/libraries/BLE/examples/BLE5_extended_scan/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_50_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/BLE5_multi_advertising/ci.json b/libraries/BLE/examples/BLE5_multi_advertising/ci.json index 9f7646a74a6..184cc25a2b0 100644 --- a/libraries/BLE/examples/BLE5_multi_advertising/ci.json +++ b/libraries/BLE/examples/BLE5_multi_advertising/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_50_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json index 9f7646a74a6..184cc25a2b0 100644 --- a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json +++ b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_50_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/BLE5_periodic_sync/ci.json b/libraries/BLE/examples/BLE5_periodic_sync/ci.json index 9f7646a74a6..184cc25a2b0 100644 --- a/libraries/BLE/examples/BLE5_periodic_sync/ci.json +++ b/libraries/BLE/examples/BLE5_periodic_sync/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_50_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/Beacon_Scanner/ci.json b/libraries/BLE/examples/Beacon_Scanner/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/Beacon_Scanner/ci.json +++ b/libraries/BLE/examples/Beacon_Scanner/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/Client/ci.json b/libraries/BLE/examples/Client/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/Client/ci.json +++ b/libraries/BLE/examples/Client/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json b/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json +++ b/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/EddystoneURL_Beacon/ci.json b/libraries/BLE/examples/EddystoneURL_Beacon/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/EddystoneURL_Beacon/ci.json +++ b/libraries/BLE/examples/EddystoneURL_Beacon/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/Notify/ci.json b/libraries/BLE/examples/Notify/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/Notify/ci.json +++ b/libraries/BLE/examples/Notify/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/Scan/ci.json b/libraries/BLE/examples/Scan/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/Scan/ci.json +++ b/libraries/BLE/examples/Scan/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/Server/ci.json b/libraries/BLE/examples/Server/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/Server/ci.json +++ b/libraries/BLE/examples/Server/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/Server_multiconnect/ci.json b/libraries/BLE/examples/Server_multiconnect/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/Server_multiconnect/ci.json +++ b/libraries/BLE/examples/Server_multiconnect/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/UART/ci.json b/libraries/BLE/examples/UART/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/UART/ci.json +++ b/libraries/BLE/examples/UART/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/Write/ci.json b/libraries/BLE/examples/Write/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/Write/ci.json +++ b/libraries/BLE/examples/Write/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BLE/examples/iBeacon/ci.json b/libraries/BLE/examples/iBeacon/ci.json index c23553ec084..abe13a7ebbb 100644 --- a/libraries/BLE/examples/iBeacon/ci.json +++ b/libraries/BLE/examples/iBeacon/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_BLE_SUPPORTED=y" ] diff --git a/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json b/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json index 98fda4381b1..b5097688f52 100644 --- a/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json +++ b/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_BT_SPP_ENABLED=y" ] diff --git a/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json b/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json index 98fda4381b1..b5097688f52 100644 --- a/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json +++ b/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_BT_SPP_ENABLED=y" ] diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json index 98fda4381b1..b5097688f52 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_BT_SPP_ENABLED=y" ] diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json index 98fda4381b1..b5097688f52 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_BT_SPP_ENABLED=y" ] diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json index 98fda4381b1..b5097688f52 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_BT_SPP_ENABLED=y" ] diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json index 98fda4381b1..b5097688f52 100644 --- a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json +++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_BT_SPP_ENABLED=y" ] diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json index 98fda4381b1..b5097688f52 100644 --- a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json +++ b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_BT_SPP_ENABLED=y" ] diff --git a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json index 98fda4381b1..b5097688f52 100644 --- a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json +++ b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_BT_SPP_ENABLED=y" ] diff --git a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json index 36babb82730..04eb62b977a 100644 --- a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json +++ b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y" ] diff --git a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json index 36babb82730..04eb62b977a 100644 --- a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json +++ b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y" ] diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json index 36babb82730..04eb62b977a 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y" ] diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json index 36babb82730..04eb62b977a 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json @@ -1,4 +1,5 @@ { + "fqbn_append": "PartitionScheme=huge_app", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y" ] From 0d5d50eb4186cb5ef0b7c108f87fae1cb688b84f Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 7 Oct 2024 09:56:04 -0300 Subject: [PATCH 049/406] feat(uart): eliminates nonexistent functions (#10428) loop() calls Serial Events functions when those are declared. The way it was declared was forcing to alway call avalable() to then call an empty function. This commit fixes it. --- cores/esp32/HardwareSerial.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 2e1f2701e9a..c82cbb43d3b 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -24,16 +24,13 @@ #endif void serialEvent(void) __attribute__((weak)); -void serialEvent(void) {} #if SOC_UART_NUM > 1 void serialEvent1(void) __attribute__((weak)); -void serialEvent1(void) {} #endif /* SOC_UART_NUM > 1 */ #if SOC_UART_NUM > 2 void serialEvent2(void) __attribute__((weak)); -void serialEvent2(void) {} #endif /* SOC_UART_NUM > 2 */ #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) @@ -48,37 +45,35 @@ HardwareSerial Serial2(2); #if HWCDC_SERIAL_IS_DEFINED == 1 // Hardware JTAG CDC Event extern void HWCDCSerialEvent(void) __attribute__((weak)); -void HWCDCSerialEvent(void) {} #endif #if USB_SERIAL_IS_DEFINED == 1 // Native USB CDC Event // Used by Hardware Serial for USB CDC events extern void USBSerialEvent(void) __attribute__((weak)); -void USBSerialEvent(void) {} #endif void serialEventRun(void) { #if HWCDC_SERIAL_IS_DEFINED == 1 // Hardware JTAG CDC Event - if (HWCDCSerial.available()) { + if (HWCDCSerialEvent && HWCDCSerial.available()) { HWCDCSerialEvent(); } #endif #if USB_SERIAL_IS_DEFINED == 1 // Native USB CDC Event - if (USBSerial.available()) { + if (USBSerialEvent && USBSerial.available()) { USBSerialEvent(); } #endif // UART0 is default serialEvent() - if (Serial0.available()) { + if (serialEvent && Serial0.available()) { serialEvent(); } #if SOC_UART_NUM > 1 - if (Serial1.available()) { + if (serialEvent1 && Serial1.available()) { serialEvent1(); } #endif #if SOC_UART_NUM > 2 - if (Serial2.available()) { + if (serialEvent2 && Serial2.available()) { serialEvent2(); } #endif From 3445164e2d9042189f79f76568a548d4e7ff9a81 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 7 Oct 2024 09:56:41 -0300 Subject: [PATCH 050/406] test(psram): Add PSRAM test (#10409) * test(psram): Add PSRAM test * fix(test): Hide pointer arithmetic warning * ci(pre-commit): Apply automatic fixes * fix(json): Remove FQBNs for the test --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- tests/validation/psram/ci.json | 14 ++++ tests/validation/psram/psram.ino | 112 +++++++++++++++++++++++++++ tests/validation/psram/test_psram.py | 2 + 3 files changed, 128 insertions(+) create mode 100644 tests/validation/psram/ci.json create mode 100644 tests/validation/psram/psram.ino create mode 100644 tests/validation/psram/test_psram.py diff --git a/tests/validation/psram/ci.json b/tests/validation/psram/ci.json new file mode 100644 index 00000000000..fc34574cf37 --- /dev/null +++ b/tests/validation/psram/ci.json @@ -0,0 +1,14 @@ +{ + "platforms": { + "qemu": false, + "wokwi": false + }, + "requires": [ + "CONFIG_SPIRAM=y" + ], + "targets": { + "esp32c3": false, + "esp32c6": false, + "esp32h2": false + } +} diff --git a/tests/validation/psram/psram.ino b/tests/validation/psram/psram.ino new file mode 100644 index 00000000000..1304fe85cc1 --- /dev/null +++ b/tests/validation/psram/psram.ino @@ -0,0 +1,112 @@ +#include +#include + +#define MAX_TEST_SIZE 512 * 1024 // 512KB + +void *buf = NULL; + +void test_malloc_success(void) { + buf = ps_malloc(MAX_TEST_SIZE); + TEST_ASSERT_NOT_NULL(buf); + free(buf); + buf = NULL; +} + +void test_calloc_success(void) { + buf = ps_calloc(MAX_TEST_SIZE, 1); + TEST_ASSERT_NOT_NULL(buf); + free(buf); + buf = NULL; +} + +void test_realloc_success(void) { + buf = ps_malloc(MAX_TEST_SIZE); + TEST_ASSERT_NOT_NULL(buf); + buf = ps_realloc(buf, MAX_TEST_SIZE + 1024); + TEST_ASSERT_NOT_NULL(buf); + free(buf); + buf = NULL; +} + +void test_malloc_fail(void) { + buf = ps_malloc(0xFFFFFFFF); + TEST_ASSERT_NULL(buf); +} + +void test_memset_all_zeroes(void) { + memset(buf, 0, MAX_TEST_SIZE); + for (size_t i = 0; i < MAX_TEST_SIZE; i++) { + TEST_ASSERT_EQUAL(0, ((uint8_t *)buf)[i]); + } +} + +void test_memset_all_ones(void) { + memset(buf, 0xFF, MAX_TEST_SIZE); + for (size_t i = 0; i < MAX_TEST_SIZE; i++) { + TEST_ASSERT_EQUAL(0xFF, ((uint8_t *)buf)[i]); + } +} + +void test_memset_alternating(void) { + for (size_t i = 0; i < MAX_TEST_SIZE; i++) { + ((uint8_t *)buf)[i] = i % 2 == 0 ? 0x00 : 0xFF; + } + memset(buf, 0xAA, MAX_TEST_SIZE); + for (size_t i = 0; i < MAX_TEST_SIZE; i++) { + TEST_ASSERT_EQUAL(0xAA, ((uint8_t *)buf)[i]); + } +} + +void test_memset_random(void) { + for (size_t i = 0; i < MAX_TEST_SIZE; i++) { + ((uint8_t *)buf)[i] = random(0, 256); + } + memset(buf, 0x55, MAX_TEST_SIZE); + for (size_t i = 0; i < MAX_TEST_SIZE; i++) { + TEST_ASSERT_EQUAL(0x55, ((uint8_t *)buf)[i]); + } +} + +void test_memcpy(void) { + void *buf2 = malloc(1024); // 1KB + TEST_ASSERT_NOT_NULL(buf2); + memset(buf, 0x55, MAX_TEST_SIZE); + memset(buf2, 0xAA, 1024); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-arith" + + for (size_t i = 0; i < MAX_TEST_SIZE; i += 1024) { + memcpy(buf + i, buf2, 1024); + } + + for (size_t i = 0; i < MAX_TEST_SIZE; i += 1024) { + TEST_ASSERT_NULL(memcmp(buf + i, buf2, 1024)); + } + +#pragma GCC diagnostic pop + + free(buf2); +} + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + UNITY_BEGIN(); + RUN_TEST(test_malloc_success); + RUN_TEST(test_malloc_fail); + RUN_TEST(test_calloc_success); + RUN_TEST(test_realloc_success); + buf = ps_malloc(MAX_TEST_SIZE); + RUN_TEST(test_memset_all_zeroes); + RUN_TEST(test_memset_all_ones); + RUN_TEST(test_memset_alternating); + RUN_TEST(test_memset_random); + RUN_TEST(test_memcpy); + UNITY_END(); +} + +void loop() {} diff --git a/tests/validation/psram/test_psram.py b/tests/validation/psram/test_psram.py new file mode 100644 index 00000000000..7bd1d9d735d --- /dev/null +++ b/tests/validation/psram/test_psram.py @@ -0,0 +1,2 @@ +def test_psram(dut): + dut.expect_unity_test_output(timeout=120) From ba9a3a1dbd5247f662932d4d505b9b1da6ae369c Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 7 Oct 2024 10:58:41 -0300 Subject: [PATCH 051/406] fix(arduino): adds ESP32-P4 to the package description (#10426) * fix(arduino): adds ESP32-P4 to the package description Updates the Package description to add the P4 in 3.1.0 * fix(arduino): update readme title to add the P4 Adds ESP32-P$ to the list of supported SoC in README.md for Core 3.1.0 --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d3dca34aafe..1ee43fa0537 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Arduino core for the ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6 and ESP32-H2 +# Arduino core for the ESP32, ESP32-P4, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6 and ESP32-H2 [![Build Status](https://github.com/espressif/arduino-esp32/actions/workflows/push.yml/badge.svg?branch=master&event=push)](https://github.com/espressif/arduino-esp32/actions/workflows/push.yml) [![External Libraries Test](https://github.com/espressif/arduino-esp32/actions/workflows/lib.yml/badge.svg?branch=master&event=schedule)](https://github.com/espressif/arduino-esp32/blob/gh-pages/LIBRARIES_TEST.md) [![Hardware Tests](https://github.com/espressif/arduino-esp32/blob/gh-pages/runtime-tests-results/badge.svg)](https://github.com/espressif/arduino-esp32/actions/workflows/tests_results.yml) diff --git a/package.json b/package.json index 2e53f41d4c8..e13a446bd98 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "framework-arduinoespressif32", "version": "3.1.0", - "description": "Arduino Wiring-based Framework for the Espressif ESP32, ESP32-S and ESP32-C series of SoCs", + "description": "Arduino Wiring-based Framework for the Espressif ESP32, ESP32-P4, ESP32-S and ESP32-C series of SoCs", "keywords": [ "framework", "arduino", From f083e2df8d9d58a59e86fd2c089ca60490f898b5 Mon Sep 17 00:00:00 2001 From: Hamza Hajeir <32960423+HamzaHajeir@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:15:42 +0300 Subject: [PATCH 052/406] fix(asyncudp): Fixes and implements tcpip thread locking (#10415) * fix(asyncudp): Fixes and implements tcpip thread locking * fix(asyncudp): Adds missing unlock * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- libraries/AsyncUDP/src/AsyncUDP.cpp | 39 ++++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/libraries/AsyncUDP/src/AsyncUDP.cpp b/libraries/AsyncUDP/src/AsyncUDP.cpp index 4f799b4d4a4..5549276de44 100644 --- a/libraries/AsyncUDP/src/AsyncUDP.cpp +++ b/libraries/AsyncUDP/src/AsyncUDP.cpp @@ -15,6 +15,21 @@ extern "C" { #include "lwip/priv/tcpip_priv.h" +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING +#define UDP_MUTEX_LOCK() \ + if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ + LOCK_TCPIP_CORE(); \ + } + +#define UDP_MUTEX_UNLOCK() \ + if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ + UNLOCK_TCPIP_CORE(); \ + } +#else // CONFIG_LWIP_TCPIP_CORE_LOCKING +#define UDP_MUTEX_LOCK() +#define UDP_MUTEX_UNLOCK() +#endif // CONFIG_LWIP_TCPIP_CORE_LOCKING + static const char *netif_ifkeys[TCPIP_ADAPTER_IF_MAX] = {"WIFI_STA_DEF", "WIFI_AP_DEF", "ETH_DEF", "PPP_DEF"}; static esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void **netif) { @@ -28,7 +43,9 @@ static esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void **net if (netif_index < 0) { return ESP_FAIL; } + UDP_MUTEX_LOCK(); *netif = (void *)netif_get_by_index(netif_index); + UDP_MUTEX_UNLOCK(); } else { *netif = netif_default; } @@ -232,9 +249,6 @@ static bool _udp_task_stop(){ } */ -#define UDP_MUTEX_LOCK() //xSemaphoreTake(_lock, portMAX_DELAY) -#define UDP_MUTEX_UNLOCK() //xSemaphoreGive(_lock) - AsyncUDPMessage::AsyncUDPMessage(size_t size) { _index = 0; if (size > CONFIG_TCP_MSS) { @@ -473,12 +487,14 @@ bool AsyncUDP::_init() { if (_pcb) { return true; } + UDP_MUTEX_LOCK(); _pcb = udp_new(); if (!_pcb) { + UDP_MUTEX_UNLOCK(); return false; } - //_lock = xSemaphoreCreateMutex(); udp_recv(_pcb, &_udp_recv, (void *)this); + UDP_MUTEX_UNLOCK(); return true; } @@ -493,14 +509,12 @@ AsyncUDP::~AsyncUDP() { close(); UDP_MUTEX_LOCK(); udp_recv(_pcb, NULL, NULL); + UDP_MUTEX_UNLOCK(); _udp_remove(_pcb); _pcb = NULL; - UDP_MUTEX_UNLOCK(); - //vSemaphoreDelete(_lock); } void AsyncUDP::close() { - UDP_MUTEX_LOCK(); if (_pcb != NULL) { if (_connected) { _udp_disconnect(_pcb); @@ -508,7 +522,6 @@ void AsyncUDP::close() { _connected = false; //todo: unjoin multicast group } - UDP_MUTEX_UNLOCK(); } bool AsyncUDP::connect(const ip_addr_t *addr, uint16_t port) { @@ -520,14 +533,11 @@ bool AsyncUDP::connect(const ip_addr_t *addr, uint16_t port) { return false; } close(); - UDP_MUTEX_LOCK(); _lastErr = _udp_connect(_pcb, addr, port); if (_lastErr != ERR_OK) { - UDP_MUTEX_UNLOCK(); return false; } _connected = true; - UDP_MUTEX_UNLOCK(); return true; } @@ -544,13 +554,10 @@ bool AsyncUDP::listen(const ip_addr_t *addr, uint16_t port) { IP_SET_TYPE_VAL(_pcb->local_ip, addr->type); IP_SET_TYPE_VAL(_pcb->remote_ip, addr->type); } - UDP_MUTEX_LOCK(); if (_udp_bind(_pcb, addr, port) != ERR_OK) { - UDP_MUTEX_UNLOCK(); return false; } _connected = true; - UDP_MUTEX_UNLOCK(); return true; } @@ -624,12 +631,10 @@ bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl return false; } - UDP_MUTEX_LOCK(); _pcb->mcast_ttl = ttl; _pcb->remote_port = port; ip_addr_copy(_pcb->remote_ip, *addr); //ip_addr_copy(_pcb->remote_ip, ip_addr_any_type); - UDP_MUTEX_UNLOCK(); return true; } @@ -651,7 +656,6 @@ size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const ip_addr_t *addr, if (pbt != NULL) { uint8_t *dst = reinterpret_cast(pbt->payload); memcpy(dst, data, len); - UDP_MUTEX_LOCK(); if (tcpip_if < TCPIP_ADAPTER_IF_MAX) { void *nif = NULL; tcpip_adapter_get_netif((tcpip_adapter_if_t)tcpip_if, &nif); @@ -663,7 +667,6 @@ size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const ip_addr_t *addr, } else { _lastErr = _udp_sendto(_pcb, pbt, addr, port); } - UDP_MUTEX_UNLOCK(); pbuf_free(pbt); if (_lastErr < ERR_OK) { return 0; From af4099202dba9acbb2653f3579e6441e65556bf4 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 10 Oct 2024 17:22:39 +0300 Subject: [PATCH 053/406] IDF release/v5.3 (#10444) * IDF release/v5.3 707d097b * fix(camera): Remove support for face detection and recognition --- .../Camera/CameraWebServer/app_httpd.cpp | 520 +----------------- package/package_esp32_index.template.json | 32 +- 2 files changed, 37 insertions(+), 515 deletions(-) diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp b/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp index af3d38ad544..6b62ee9b6cf 100644 --- a/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp +++ b/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp @@ -24,55 +24,6 @@ #include "esp32-hal-log.h" #endif -// Face Detection will not work on boards without (or with disabled) PSRAM -#ifdef BOARD_HAS_PSRAM -// Face Recognition takes upward from 15 seconds per frame on chips other than ESP32S3 -// Makes no sense to have it enabled for them -#if CONFIG_IDF_TARGET_ESP32S3 -#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 1 -#define CONFIG_ESP_FACE_DETECT_ENABLED 1 -#else -#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0 -#define CONFIG_ESP_FACE_DETECT_ENABLED 0 -#endif -#else -#define CONFIG_ESP_FACE_DETECT_ENABLED 0 -#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0 -#endif - -#if CONFIG_ESP_FACE_DETECT_ENABLED - -#include -#include "human_face_detect_msr01.hpp" -#include "human_face_detect_mnp01.hpp" - -#define TWO_STAGE 1 /* very large firmware, very slow, reboots when streaming... - -#define FACE_ID_SAVE_NUMBER 7 -#endif - -#define FACE_COLOR_WHITE 0x00FFFFFF -#define FACE_COLOR_BLACK 0x00000000 -#define FACE_COLOR_RED 0x000000FF -#define FACE_COLOR_GREEN 0x0000FF00 -#define FACE_COLOR_BLUE 0x00FF0000 -#define FACE_COLOR_YELLOW (FACE_COLOR_RED | FACE_COLOR_GREEN) -#define FACE_COLOR_CYAN (FACE_COLOR_BLUE | FACE_COLOR_GREEN) -#define FACE_COLOR_PURPLE (FACE_COLOR_BLUE | FACE_COLOR_RED) -#endif - // Enable LED FLASH setting #define CONFIG_LED_ILLUMINATOR_ENABLED 1 @@ -100,32 +51,6 @@ static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: % httpd_handle_t stream_httpd = NULL; httpd_handle_t camera_httpd = NULL; -#if CONFIG_ESP_FACE_DETECT_ENABLED - -static int8_t detection_enabled = 0; - -// #if TWO_STAGE -// static HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F); -// static HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5); -// #else -// static HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F); -// #endif - -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED -static int8_t recognition_enabled = 0; -static int8_t is_enrolling = 0; - -#if QUANT_TYPE -// S16 model -FaceRecognition112V1S16 recognizer; -#else -// S8 model -FaceRecognition112V1S8 recognizer; -#endif -#endif - -#endif - typedef struct { size_t size; //number of values used for filtering size_t index; //current value index @@ -166,105 +91,6 @@ static int ra_filter_run(ra_filter_t *filter, int value) { } #endif -#if CONFIG_ESP_FACE_DETECT_ENABLED -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED -static void rgb_print(fb_data_t *fb, uint32_t color, const char *str) { - fb_gfx_print(fb, (fb->width - (strlen(str) * 14)) / 2, 10, color, str); -} - -static int rgb_printf(fb_data_t *fb, uint32_t color, const char *format, ...) { - char loc_buf[64]; - char *temp = loc_buf; - int len; - va_list arg; - va_list copy; - va_start(arg, format); - va_copy(copy, arg); - len = vsnprintf(loc_buf, sizeof(loc_buf), format, arg); - va_end(copy); - if (len >= sizeof(loc_buf)) { - temp = (char *)malloc(len + 1); - if (temp == NULL) { - return 0; - } - } - vsnprintf(temp, len + 1, format, arg); - va_end(arg); - rgb_print(fb, color, temp); - if (len > 64) { - free(temp); - } - return len; -} -#endif -static void draw_face_boxes(fb_data_t *fb, std::list *results, int face_id) { - int x, y, w, h; - uint32_t color = FACE_COLOR_YELLOW; - if (face_id < 0) { - color = FACE_COLOR_RED; - } else if (face_id > 0) { - color = FACE_COLOR_GREEN; - } - if (fb->bytes_per_pixel == 2) { - //color = ((color >> 8) & 0xF800) | ((color >> 3) & 0x07E0) | (color & 0x001F); - color = ((color >> 16) & 0x001F) | ((color >> 3) & 0x07E0) | ((color << 8) & 0xF800); - } - int i = 0; - for (std::list::iterator prediction = results->begin(); prediction != results->end(); prediction++, i++) { - // rectangle box - x = (int)prediction->box[0]; - y = (int)prediction->box[1]; - w = (int)prediction->box[2] - x + 1; - h = (int)prediction->box[3] - y + 1; - if ((x + w) > fb->width) { - w = fb->width - x; - } - if ((y + h) > fb->height) { - h = fb->height - y; - } - fb_gfx_drawFastHLine(fb, x, y, w, color); - fb_gfx_drawFastHLine(fb, x, y + h - 1, w, color); - fb_gfx_drawFastVLine(fb, x, y, h, color); - fb_gfx_drawFastVLine(fb, x + w - 1, y, h, color); -#if TWO_STAGE - // landmarks (left eye, mouth left, nose, right eye, mouth right) - int x0, y0, j; - for (j = 0; j < 10; j += 2) { - x0 = (int)prediction->keypoint[j]; - y0 = (int)prediction->keypoint[j + 1]; - fb_gfx_fillRect(fb, x0, y0, 3, 3, color); - } -#endif - } -} - -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED -static int run_face_recognition(fb_data_t *fb, std::list *results) { - std::vector landmarks = results->front().keypoint; - int id = -1; - - Tensor tensor; - tensor.set_element((uint8_t *)fb->data).set_shape({fb->height, fb->width, 3}).set_auto_free(false); - - int enrolled_count = recognizer.get_enrolled_id_num(); - - if (enrolled_count < FACE_ID_SAVE_NUMBER && is_enrolling) { - id = recognizer.enroll_id(tensor, landmarks, "", true); - log_i("Enrolled ID: %d", id); - rgb_printf(fb, FACE_COLOR_CYAN, "ID[%u]", id); - } - - face_info_t recognize = recognizer.recognize(tensor, landmarks); - if (recognize.id >= 0) { - rgb_printf(fb, FACE_COLOR_GREEN, "ID[%u]: %.2f", recognize.id, recognize.similarity); - } else { - rgb_print(fb, FACE_COLOR_RED, "Intruder Alert!"); - } - return recognize.id; -} -#endif -#endif - #if CONFIG_LED_ILLUMINATOR_ENABLED void enable_led(bool en) { // Turn LED On or Off int duty = en ? led_duty : 0; @@ -359,134 +185,28 @@ static esp_err_t capture_handler(httpd_req_t *req) { snprintf(ts, 32, "%lld.%06ld", fb->timestamp.tv_sec, fb->timestamp.tv_usec); httpd_resp_set_hdr(req, "X-Timestamp", (const char *)ts); -#if CONFIG_ESP_FACE_DETECT_ENABLED - size_t out_len, out_width, out_height; - uint8_t *out_buf; - bool s; -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - bool detected = false; -#endif - int face_id = 0; - if (!detection_enabled || fb->width > 400) { -#endif #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - size_t fb_len = 0; + size_t fb_len = 0; #endif - if (fb->format == PIXFORMAT_JPEG) { + if (fb->format == PIXFORMAT_JPEG) { #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fb_len = fb->len; + fb_len = fb->len; #endif - res = httpd_resp_send(req, (const char *)fb->buf, fb->len); - } else { - jpg_chunking_t jchunk = {req, 0}; - res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL; - httpd_resp_send_chunk(req, NULL, 0); -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fb_len = jchunk.len; -#endif - } - esp_camera_fb_return(fb); -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - int64_t fr_end = esp_timer_get_time(); -#endif - log_i("JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000)); - return res; -#if CONFIG_ESP_FACE_DETECT_ENABLED - } - - jpg_chunking_t jchunk = {req, 0}; - - if (fb->format == PIXFORMAT_RGB565 -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED - && !recognition_enabled -#endif - ) { -#if TWO_STAGE - HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F); - HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5); - std::list &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}); - std::list &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates); -#else - HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F); - std::list &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}); -#endif - if (results.size() > 0) { - fb_data_t rfb; - rfb.width = fb->width; - rfb.height = fb->height; - rfb.data = fb->buf; - rfb.bytes_per_pixel = 2; - rfb.format = FB_RGB565; -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - detected = true; -#endif - draw_face_boxes(&rfb, &results, face_id); - } - s = fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 90, jpg_encode_stream, &jchunk); - esp_camera_fb_return(fb); + res = httpd_resp_send(req, (const char *)fb->buf, fb->len); } else { - out_len = fb->width * fb->height * 3; - out_width = fb->width; - out_height = fb->height; - out_buf = (uint8_t *)malloc(out_len); - if (!out_buf) { - log_e("out_buf malloc failed"); - httpd_resp_send_500(req); - return ESP_FAIL; - } - s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf); - esp_camera_fb_return(fb); - if (!s) { - free(out_buf); - log_e("To rgb888 failed"); - httpd_resp_send_500(req); - return ESP_FAIL; - } - - fb_data_t rfb; - rfb.width = out_width; - rfb.height = out_height; - rfb.data = out_buf; - rfb.bytes_per_pixel = 3; - rfb.format = FB_BGR888; - -#if TWO_STAGE - HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F); - HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5); - std::list &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}); - std::list &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates); -#else - HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F); - std::list &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}); -#endif - - if (results.size() > 0) { + jpg_chunking_t jchunk = {req, 0}; + res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL; + httpd_resp_send_chunk(req, NULL, 0); #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - detected = true; + fb_len = jchunk.len; #endif -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED - if (recognition_enabled) { - face_id = run_face_recognition(&rfb, &results); - } -#endif - draw_face_boxes(&rfb, &results, face_id); - } - - s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk); - free(out_buf); - } - - if (!s) { - log_e("JPEG compression failed"); - httpd_resp_send_500(req); - return ESP_FAIL; } + esp_camera_fb_return(fb); #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO int64_t fr_end = esp_timer_get_time(); #endif - log_i("FACE: %uB %ums %s%d", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start) / 1000), detected ? "DETECTED " : "", face_id); + log_i("JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000)); return res; -#endif } static esp_err_t stream_handler(httpd_req_t *req) { @@ -496,26 +216,6 @@ static esp_err_t stream_handler(httpd_req_t *req) { size_t _jpg_buf_len = 0; uint8_t *_jpg_buf = NULL; char *part_buf[128]; -#if CONFIG_ESP_FACE_DETECT_ENABLED -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - bool detected = false; - int64_t fr_ready = 0; - int64_t fr_recognize = 0; - int64_t fr_encode = 0; - int64_t fr_face = 0; - int64_t fr_start = 0; -#endif - int face_id = 0; - size_t out_len = 0, out_width = 0, out_height = 0; - uint8_t *out_buf = NULL; - bool s = false; -#if TWO_STAGE - HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F); - HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5); -#else - HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F); -#endif -#endif static int64_t last_frame = 0; if (!last_frame) { @@ -536,13 +236,6 @@ static esp_err_t stream_handler(httpd_req_t *req) { #endif while (true) { -#if CONFIG_ESP_FACE_DETECT_ENABLED -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - detected = false; -#endif - face_id = 0; -#endif - fb = esp_camera_fb_get(); if (!fb) { log_e("Camera capture failed"); @@ -550,138 +243,18 @@ static esp_err_t stream_handler(httpd_req_t *req) { } else { _timestamp.tv_sec = fb->timestamp.tv_sec; _timestamp.tv_usec = fb->timestamp.tv_usec; -#if CONFIG_ESP_FACE_DETECT_ENABLED -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fr_start = esp_timer_get_time(); - fr_ready = fr_start; - fr_encode = fr_start; - fr_recognize = fr_start; - fr_face = fr_start; -#endif - if (!detection_enabled || fb->width > 400) { -#endif - if (fb->format != PIXFORMAT_JPEG) { - bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); - esp_camera_fb_return(fb); - fb = NULL; - if (!jpeg_converted) { - log_e("JPEG compression failed"); - res = ESP_FAIL; - } - } else { - _jpg_buf_len = fb->len; - _jpg_buf = fb->buf; + if (fb->format != PIXFORMAT_JPEG) { + bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); + esp_camera_fb_return(fb); + fb = NULL; + if (!jpeg_converted) { + log_e("JPEG compression failed"); + res = ESP_FAIL; } -#if CONFIG_ESP_FACE_DETECT_ENABLED } else { - if (fb->format == PIXFORMAT_RGB565 -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED - && !recognition_enabled -#endif - ) { -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fr_ready = esp_timer_get_time(); -#endif -#if TWO_STAGE - std::list &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}); - std::list &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates); -#else - std::list &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}); -#endif -#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fr_face = esp_timer_get_time(); - fr_recognize = fr_face; -#endif - if (results.size() > 0) { - fb_data_t rfb; - rfb.width = fb->width; - rfb.height = fb->height; - rfb.data = fb->buf; - rfb.bytes_per_pixel = 2; - rfb.format = FB_RGB565; -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - detected = true; -#endif - draw_face_boxes(&rfb, &results, face_id); - } - s = fmt2jpg(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 80, &_jpg_buf, &_jpg_buf_len); - esp_camera_fb_return(fb); - fb = NULL; - if (!s) { - log_e("fmt2jpg failed"); - res = ESP_FAIL; - } -#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fr_encode = esp_timer_get_time(); -#endif - } else { - out_len = fb->width * fb->height * 3; - out_width = fb->width; - out_height = fb->height; - out_buf = (uint8_t *)malloc(out_len); - if (!out_buf) { - log_e("out_buf malloc failed"); - res = ESP_FAIL; - } else { - s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf); - esp_camera_fb_return(fb); - fb = NULL; - if (!s) { - free(out_buf); - log_e("To rgb888 failed"); - res = ESP_FAIL; - } else { -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fr_ready = esp_timer_get_time(); -#endif - - fb_data_t rfb; - rfb.width = out_width; - rfb.height = out_height; - rfb.data = out_buf; - rfb.bytes_per_pixel = 3; - rfb.format = FB_BGR888; - -#if TWO_STAGE - std::list &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}); - std::list &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates); -#else - std::list &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}); -#endif - -#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fr_face = esp_timer_get_time(); - fr_recognize = fr_face; -#endif - - if (results.size() > 0) { -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - detected = true; -#endif -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED - if (recognition_enabled) { - face_id = run_face_recognition(&rfb, &results); -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fr_recognize = esp_timer_get_time(); -#endif - } -#endif - draw_face_boxes(&rfb, &results, face_id); - } - s = fmt2jpg(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len); - free(out_buf); - if (!s) { - log_e("fmt2jpg failed"); - res = ESP_FAIL; - } -#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - fr_encode = esp_timer_get_time(); -#endif - } - } - } + _jpg_buf_len = fb->len; + _jpg_buf = fb->buf; } -#endif } if (res == ESP_OK) { res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); @@ -707,30 +280,14 @@ static esp_err_t stream_handler(httpd_req_t *req) { } int64_t fr_end = esp_timer_get_time(); -#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO - int64_t ready_time = (fr_ready - fr_start) / 1000; - int64_t face_time = (fr_face - fr_ready) / 1000; - int64_t recognize_time = (fr_recognize - fr_face) / 1000; - int64_t encode_time = (fr_encode - fr_recognize) / 1000; - int64_t process_time = (fr_encode - fr_start) / 1000; -#endif - int64_t frame_time = fr_end - last_frame; frame_time /= 1000; #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time); #endif log_i( - "MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)" -#if CONFIG_ESP_FACE_DETECT_ENABLED - ", %u+%u+%u+%u=%u %s%d" -#endif - , - (uint32_t)(_jpg_buf_len), (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time, avg_frame_time, 1000.0 / avg_frame_time -#if CONFIG_ESP_FACE_DETECT_ENABLED - , - (uint32_t)ready_time, (uint32_t)face_time, (uint32_t)recognize_time, (uint32_t)encode_time, (uint32_t)process_time, (detected) ? "DETECTED " : "", face_id -#endif + "MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)", (uint32_t)(_jpg_buf_len), (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time, avg_frame_time, + 1000.0 / avg_frame_time ); } @@ -841,28 +398,6 @@ static esp_err_t cmd_handler(httpd_req_t *req) { enable_led(true); } } -#endif - -#if CONFIG_ESP_FACE_DETECT_ENABLED - else if (!strcmp(variable, "face_detect")) { - detection_enabled = val; -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED - if (!detection_enabled) { - recognition_enabled = 0; - } -#endif - } -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED - else if (!strcmp(variable, "face_enroll")) { - is_enrolling = !is_enrolling; - log_i("Enrolling: %s", is_enrolling ? "true" : "false"); - } else if (!strcmp(variable, "face_recognize")) { - recognition_enabled = val; - if (recognition_enabled) { - detection_enabled = val; - } - } -#endif #endif else { log_i("Unknown command: %s", variable); @@ -947,13 +482,6 @@ static esp_err_t status_handler(httpd_req_t *req) { p += sprintf(p, ",\"led_intensity\":%u", led_duty); #else p += sprintf(p, ",\"led_intensity\":%d", -1); -#endif -#if CONFIG_ESP_FACE_DETECT_ENABLED - p += sprintf(p, ",\"face_detect\":%u", detection_enabled); -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED - p += sprintf(p, ",\"face_enroll\":%u,", is_enrolling); - p += sprintf(p, "\"face_recognize\":%u", recognition_enabled); -#endif #endif *p++ = '}'; *p++ = 0; @@ -1289,12 +817,6 @@ void startCameraServer() { ra_filter_init(&ra_filter, 20); -#if CONFIG_ESP_FACE_RECOGNITION_ENABLED - recognizer.set_partition(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "fr"); - - // load ids from flash partition - recognizer.set_ids_from_flash(); -#endif log_i("Starting web server on port: '%d'", config.server_port); if (httpd_start(&camera_httpd, &config) == ESP_OK) { httpd_register_uri_handler(camera_httpd, &index_uri); diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index ea66c5a816d..413419a9b1c 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -101,57 +101,57 @@ "host": "i686-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", - "size": "399729605" + "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", + "size": "351074410" }, { "host": "x86_64-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", - "size": "399729605" + "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", + "size": "351074410" }, { "host": "arm64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", - "size": "399729605" + "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", + "size": "351074410" }, { "host": "x86_64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", - "size": "399729605" + "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", + "size": "351074410" }, { "host": "x86_64-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", - "size": "399729605" + "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", + "size": "351074410" }, { "host": "i686-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", - "size": "399729605" + "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", + "size": "351074410" }, { "host": "aarch64-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", - "size": "399729605" + "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", + "size": "351074410" }, { "host": "arm-linux-gnueabihf", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:f8624bf7eab91e0a3bb3be4cc385fef5a05a725bc6ff978f3d4e2562f2805b1e", - "size": "399729605" + "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", + "size": "351074410" } ] }, From 81d2cbca961fd7718f7af350677cb5e6561d7784 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:27:04 -0300 Subject: [PATCH 054/406] fix(uart): Add missing HP UARTs for ESP32-P4 (#10447) * fix(uart): Add missing HP UARTs for ESP32-P4 * fix(comment): Fix macro in comment * fix(uart): Fix macro guard --- cores/esp32/HardwareSerial.cpp | 32 ++++++++++++++++++++++++++++---- cores/esp32/HardwareSerial.h | 6 ++++++ cores/esp32/esp32-hal-uart.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index f515e833925..a6a7573f6e3 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -27,11 +27,19 @@ void serialEvent(void) __attribute__((weak)); #if SOC_UART_HP_NUM > 1 void serialEvent1(void) __attribute__((weak)); -#endif /* SOC_UART_NUM > 1 */ +#endif /* SOC_UART_HP_NUM > 1 */ #if SOC_UART_HP_NUM > 2 void serialEvent2(void) __attribute__((weak)); -#endif /* SOC_UART_NUM > 2 */ +#endif /* SOC_UART_HP_NUM > 2 */ + +#if SOC_UART_HP_NUM > 3 +void serialEvent3(void) __attribute__((weak)); +#endif /* SOC_UART_HP_NUM > 3 */ + +#if SOC_UART_HP_NUM > 4 +void serialEvent4(void) __attribute__((weak)); +#endif /* SOC_UART_HP_NUM > 4 */ #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) // There is always Seria0 for UART0 @@ -42,6 +50,12 @@ HardwareSerial Serial1(1); #if SOC_UART_HP_NUM > 2 HardwareSerial Serial2(2); #endif +#if SOC_UART_HP_NUM > 3 +HardwareSerial Serial3(3); +#endif +#if SOC_UART_HP_NUM > 4 +HardwareSerial Serial4(4); +#endif #if HWCDC_SERIAL_IS_DEFINED == 1 // Hardware JTAG CDC Event extern void HWCDCSerialEvent(void) __attribute__((weak)); @@ -67,16 +81,26 @@ void serialEventRun(void) { if (serialEvent && Serial0.available()) { serialEvent(); } -#if SOC_UART_NUM > 1 +#if SOC_UART_HP_NUM > 1 if (serialEvent1 && Serial1.available()) { serialEvent1(); } #endif -#if SOC_UART_NUM > 2 +#if SOC_UART_HP_NUM > 2 if (serialEvent2 && Serial2.available()) { serialEvent2(); } #endif +#if SOC_UART_HP_NUM > 3 + if (serialEvent3 && Serial3.available()) { + serialEvent3(); + } +#endif +#if SOC_UART_HP_NUM > 4 + if (serialEvent4 && Serial4.available()) { + serialEvent4(); + } +#endif } #endif diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index fc5dd92440d..8eb7f2c91a6 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -375,6 +375,12 @@ extern HardwareSerial Serial1; #if SOC_UART_HP_NUM > 2 extern HardwareSerial Serial2; #endif +#if SOC_UART_HP_NUM > 3 +extern HardwareSerial Serial3; +#endif +#if SOC_UART_HP_NUM > 4 +extern HardwareSerial Serial4; +#endif #endif //!defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) #endif // HardwareSerial_h diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 82c9d8808d0..706124c7451 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -67,6 +67,12 @@ static uart_t _uart_bus_array[] = { #if SOC_UART_HP_NUM > 2 {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, #endif +#if SOC_UART_HP_NUM > 3 + {3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#endif +#if SOC_UART_HP_NUM > 4 + {4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#endif }; #else @@ -87,6 +93,12 @@ static uart_t _uart_bus_array[] = { #if SOC_UART_HP_NUM > 2 {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, #endif +#if SOC_UART_HP_NUM > 3 + {NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#endif +#if SOC_UART_HP_NUM > 4 + {NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#endif }; #endif @@ -835,6 +847,20 @@ static void ARDUINO_ISR_ATTR uart2_write_char(char c) { } #endif +#if SOC_UART_HP_NUM > 3 +static void ARDUINO_ISR_ATTR uart3_write_char(char c) { + while (uart_ll_get_txfifo_len(&UART3) == 0); + uart_ll_write_txfifo(&UART3, (const uint8_t *)&c, 1); +} +#endif + +#if SOC_UART_HP_NUM > 4 +static void ARDUINO_ISR_ATTR uart4_write_char(char c) { + while (uart_ll_get_txfifo_len(&UART4) == 0); + uart_ll_write_txfifo(&UART4, (const uint8_t *)&c, 1); +} +#endif + void uart_install_putc() { switch (s_uart_debug_nr) { case 0: ets_install_putc1((void (*)(char)) & uart0_write_char); break; @@ -843,6 +869,12 @@ void uart_install_putc() { #endif #if SOC_UART_HP_NUM > 2 case 2: ets_install_putc1((void (*)(char)) & uart2_write_char); break; +#endif +#if SOC_UART_HP_NUM > 3 + case 3: ets_install_putc1((void (*)(char)) & uart3_write_char); break; +#endif +#if SOC_UART_HP_NUM > 4 + case 4: ets_install_putc1((void (*)(char)) & uart4_write_char); break; #endif default: ets_install_putc1(NULL); break; } From 3733c87c832dd7d2743fda5a42b3ff866f4c47f8 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:33:49 +0200 Subject: [PATCH 055/406] replace outdated wrong `SOC_I2C_NUM` and use `SOC_HP_I2C_NUM` (#10452) * SOC_HP_I2C_NUM * SOC_HP_I2C_NUM --- libraries/Wire/src/Wire.cpp | 4 ++-- libraries/Wire/src/Wire.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 8ac0c25595d..24b0eb7c0a3 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -646,8 +646,8 @@ void TwoWire::onRequestService(uint8_t num, void *arg) { #endif /* SOC_I2C_SUPPORT_SLAVE */ TwoWire Wire = TwoWire(0); -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 TwoWire Wire1 = TwoWire(1); -#endif /* SOC_I2C_NUM */ +#endif /* SOC_HP_I2C_NUM */ #endif /* SOC_I2C_SUPPORTED */ diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index cf720d48234..45f30c81ffc 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -144,9 +144,9 @@ class TwoWire : public HardwareI2C { }; extern TwoWire Wire; -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 extern TwoWire Wire1; -#endif /* SOC_I2C_NUM */ +#endif /* SOC_HP_I2C_NUM */ #endif /* SOC_I2C_SUPPORTED */ #endif /* TwoWire_h */ From e27a050f5ad72ab2dc666dbe68dc0342c46308e7 Mon Sep 17 00:00:00 2001 From: Y_hsiao_ch'un <66012385+Y1hsiaochunnn@users.noreply.github.com> Date: Fri, 11 Oct 2024 21:35:58 +0800 Subject: [PATCH 056/406] Added variant for Waveshare ESP32-S3-Touch-AMOLED-1.8 (#10433) --- boards.txt | 199 ++++++++++++++++++ .../pins_arduino.h | 87 ++++++++ 2 files changed, 286 insertions(+) create mode 100644 variants/waveshare_esp32_s3_touch_amoled_18/pins_arduino.h diff --git a/boards.txt b/boards.txt index 971f99a0cbc..42070a41a1c 100644 --- a/boards.txt +++ b/boards.txt @@ -40431,6 +40431,205 @@ waveshare_esp32_s3_touch_lcd_169.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +waveshare_esp32_s3_touch_amoled_18.name=Waveshare ESP32-S3-Touch-AMOLED-1.8 +waveshare_esp32_s3_touch_amoled_18.vid.0=0x303a +waveshare_esp32_s3_touch_amoled_18.pid.0=0x8255 +waveshare_esp32_s3_touch_amoled_18.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_amoled_18.upload_port.0.pid=0x8255 + +waveshare_esp32_s3_touch_amoled_18.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_amoled_18.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_amoled_18.upload.tool=esptool_py +waveshare_esp32_s3_touch_amoled_18.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_amoled_18.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_amoled_18.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_amoled_18.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_amoled_18.upload.flags= +waveshare_esp32_s3_touch_amoled_18.upload.extra_flags= +waveshare_esp32_s3_touch_amoled_18.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_amoled_18.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_amoled_18.serial.disableDTR=false +waveshare_esp32_s3_touch_amoled_18.serial.disableRTS=false + +waveshare_esp32_s3_touch_amoled_18.build.tarch=xtensa +waveshare_esp32_s3_touch_amoled_18.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_amoled_18.build.target=esp32s3 +waveshare_esp32_s3_touch_amoled_18.build.mcu=esp32s3 +waveshare_esp32_s3_touch_amoled_18.build.core=esp32 +waveshare_esp32_s3_touch_amoled_18.build.variant=waveshare_esp32_s3_touch_amoled_18 +waveshare_esp32_s3_touch_amoled_18.build.board=WAVESHARE_ESP32_S3_TOUCH_AMOLED_18 + +waveshare_esp32_s3_touch_amoled_18.build.usb_mode=1 +waveshare_esp32_s3_touch_amoled_18.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_amoled_18.build.msc_on_boot=0 +waveshare_esp32_s3_touch_amoled_18.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_amoled_18.build.f_cpu=240000000L +waveshare_esp32_s3_touch_amoled_18.build.flash_size=16MB +waveshare_esp32_s3_touch_amoled_18.build.flash_freq=80m +waveshare_esp32_s3_touch_amoled_18.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_18.build.boot=qio +waveshare_esp32_s3_touch_amoled_18.build.boot_freq=80m +waveshare_esp32_s3_touch_amoled_18.build.partitions=default +waveshare_esp32_s3_touch_amoled_18.build.defines= +waveshare_esp32_s3_touch_amoled_18.build.loop_core= +waveshare_esp32_s3_touch_amoled_18.build.event_core= +waveshare_esp32_s3_touch_amoled_18.build.psram_type=qspi +waveshare_esp32_s3_touch_amoled_18.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_amoled_18.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_amoled_18.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_amoled_18.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_amoled_18.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_amoled_18.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_amoled_18.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_amoled_18.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_amoled_18.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_amoled_18.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_amoled_18.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_amoled_18.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_amoled_18.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_amoled_18.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_amoled_18.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_amoled_18.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_amoled_18.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_amoled_18.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_amoled_18.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_amoled_18.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_amoled_18.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_18.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_amoled_18.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_amoled_18.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_amoled_18.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_18.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_amoled_18.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_amoled_18.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_amoled_18.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_18.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_amoled_18.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_amoled_18.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_amoled_18.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_amoled_18.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_amoled_18.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_amoled_18.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_amoled_18.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_amoled_18.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_amoled_18.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_amoled_18.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_amoled_18.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_amoled_18.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_amoled_18.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_amoled_18.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_amoled_18.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_amoled_18.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + waveshare_esp32_s3_lcd_169.name=Waveshare ESP32-S3-LCD-1.69 waveshare_esp32_s3_lcd_169.vid.0=0x303a waveshare_esp32_s3_lcd_169.pid.0=0x8221 diff --git a/variants/waveshare_esp32_s3_touch_amoled_18/pins_arduino.h b/variants/waveshare_esp32_s3_touch_amoled_18/pins_arduino.h new file mode 100644 index 00000000000..de8bcaec2d9 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_amoled_18/pins_arduino.h @@ -0,0 +1,87 @@ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8255 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-AMOLED-1.8" +#define USB_SERIAL "" + +// display for SH8601 +#define WS_LCD_CS 12 +#define WS_QSPI_SIO0 4 +#define WS_QSPI_SI1 5 +#define WS_QSPI_SI2 6 +#define WS_QSPI_SI3 7 +#define WS_QSPI_SCL 11 + +// Touch for FT3168 +#define WS_TP_INT 21 + +// Onboard Electric buzzer & Custom buttons +// GPIO and PSRAM conflict, need to pay attention when using + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Def for I2C that shares the IMU I2C pins +static const uint8_t SDA = 14; +static const uint8_t SCL = 15; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +// Mapping based on the ESP32S3 data sheet - alternate for OUTPUT +static const uint8_t OUTPUT_IO2 = 2; +static const uint8_t OUTPUT_IO3 = 3; +static const uint8_t OUTPUT_IO17 = 17; +static const uint8_t OUTPUT_IO18 = 18; + +// Analog capable pins on the header +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; + +// GPIO capable pins on the header +static const uint8_t D0 = 7; +static const uint8_t D1 = 6; +static const uint8_t D2 = 5; +static const uint8_t D3 = 4; +static const uint8_t D4 = 3; +static const uint8_t D5 = 2; +static const uint8_t D6 = 1; +static const uint8_t D7 = 44; +static const uint8_t D8 = 43; +static const uint8_t D9 = 40; +static const uint8_t D10 = 39; +static const uint8_t D11 = 38; +static const uint8_t D12 = 37; +static const uint8_t D13 = 36; +static const uint8_t D14 = 35; +static const uint8_t D15 = 34; +static const uint8_t D16 = 33; + +// Touch input capable pins on the header +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; + +#endif /* Pins_Arduino_h */ From 3edf5188250ddb4b4edbb44583b473105fb2e40f Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 15 Oct 2024 17:25:45 +0300 Subject: [PATCH 057/406] Add support for WiFi to ESP32-P4 (#10463) * feat(p4): Add support for WiFi to ESP32-P4 Implements support for external MCU connected through SDIO * fix(p4): Init SDIO host properly on Network boot esp-hosted has one function marked as "constructor" that did not run in the boot phase of the chip. This calls the function when network is started --- idf_component.yml | 20 ++++++++++++++------ libraries/Network/src/NetworkEvents.cpp | 2 +- libraries/Network/src/NetworkEvents.h | 13 ++++++++----- libraries/Network/src/NetworkManager.cpp | 7 +++++++ libraries/WiFi/src/AP.cpp | 2 +- libraries/WiFi/src/STA.cpp | 2 +- libraries/WiFi/src/WiFi.cpp | 2 +- libraries/WiFi/src/WiFi.h | 3 ++- libraries/WiFi/src/WiFiAP.cpp | 2 +- libraries/WiFi/src/WiFiAP.h | 2 +- libraries/WiFi/src/WiFiGeneric.cpp | 15 +++++++++++++-- libraries/WiFi/src/WiFiGeneric.h | 2 +- libraries/WiFi/src/WiFiMulti.cpp | 2 +- libraries/WiFi/src/WiFiMulti.h | 2 +- libraries/WiFi/src/WiFiSTA.cpp | 2 +- libraries/WiFi/src/WiFiSTA.h | 2 +- libraries/WiFi/src/WiFiScan.cpp | 2 +- libraries/WiFi/src/WiFiScan.h | 2 +- libraries/WiFi/src/WiFiType.h | 2 +- 19 files changed, 58 insertions(+), 28 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 3b83650bf5b..5570f5d47a5 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -56,11 +56,11 @@ dependencies: espressif/esp-zboss-lib: version: "^1.0.1" rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/esp-zigbee-lib: version: "^1.0.1" rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/esp-dsp: version: "^1.3.4" rules: @@ -68,23 +68,31 @@ dependencies: espressif/esp_rainmaker: version: "^1.0.0" rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/rmaker_common: version: "^1.4.6" rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/esp_insights: version: "^1.0.1" rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/qrcode: version: "^0.1.0~1" rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/esp-sr: version: "^1.4.2" rules: - if: "target in [esp32s3]" + espressif/esp_hosted: + version: "^0.0.22" + rules: + - if: "target == esp32p4" + espressif/esp_wifi_remote: + version: "^0.4.1" + rules: + - if: "target == esp32p4" espressif/libsodium: version: "^1.0.20~1" require: public diff --git a/libraries/Network/src/NetworkEvents.cpp b/libraries/Network/src/NetworkEvents.cpp index bb02282e9b3..4863e346a10 100644 --- a/libraries/Network/src/NetworkEvents.cpp +++ b/libraries/Network/src/NetworkEvents.cpp @@ -423,7 +423,7 @@ const char *NetworkEvents::eventName(arduino_event_id_t id) { case ARDUINO_EVENT_PPP_GOT_IP: return "PPP_GOT_IP"; case ARDUINO_EVENT_PPP_LOST_IP: return "PPP_LOST_IP"; case ARDUINO_EVENT_PPP_GOT_IP6: return "PPP_GOT_IP6"; -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED case ARDUINO_EVENT_WIFI_OFF: return "WIFI_OFF"; case ARDUINO_EVENT_WIFI_READY: return "WIFI_READY"; case ARDUINO_EVENT_WIFI_SCAN_DONE: return "SCAN_DONE"; diff --git a/libraries/Network/src/NetworkEvents.h b/libraries/Network/src/NetworkEvents.h index ac324d19841..b49951b1824 100644 --- a/libraries/Network/src/NetworkEvents.h +++ b/libraries/Network/src/NetworkEvents.h @@ -16,14 +16,15 @@ #include "freertos/queue.h" #include "freertos/semphr.h" #include "freertos/event_groups.h" +#include "sdkconfig.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include "esp_wifi_types.h" #include "esp_smartconfig.h" #include "network_provisioning/network_config.h" #endif -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED static const int WIFI_SCANNING_BIT = BIT0; static const int WIFI_SCAN_DONE_BIT = BIT1; #endif @@ -41,7 +42,7 @@ typedef enum { ARDUINO_EVENT_ETH_GOT_IP, ARDUINO_EVENT_ETH_LOST_IP, ARDUINO_EVENT_ETH_GOT_IP6, -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED ARDUINO_EVENT_WIFI_OFF, ARDUINO_EVENT_WIFI_READY, ARDUINO_EVENT_WIFI_SCAN_DONE, @@ -93,7 +94,7 @@ typedef union { ip_event_got_ip_t got_ip; ip_event_got_ip6_t got_ip6; esp_eth_handle_t eth_connected; -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED wifi_event_sta_scan_done_t wifi_scan_done; wifi_event_sta_authmode_change_t wifi_sta_authmode_change; wifi_event_sta_connected_t wifi_sta_connected; @@ -104,6 +105,8 @@ typedef union { wifi_event_ap_staconnected_t wifi_ap_staconnected; wifi_event_ap_stadisconnected_t wifi_ap_stadisconnected; wifi_event_ftm_report_t wifi_ftm_report; +#endif +#if SOC_WIFI_SUPPORTED wifi_sta_config_t prov_cred_recv; network_prov_wifi_sta_fail_reason_t prov_fail_reason; smartconfig_event_got_ssid_pswd_t sc_got_ssid_pswd; @@ -147,7 +150,7 @@ class NetworkEvents { friend class ESP_NetworkInterface; friend class ETHClass; friend class PPPClass; -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED friend class STAClass; friend class APClass; friend class WiFiGenericClass; diff --git a/libraries/Network/src/NetworkManager.cpp b/libraries/Network/src/NetworkManager.cpp index 88059a60562..b429c482825 100644 --- a/libraries/Network/src/NetworkManager.cpp +++ b/libraries/Network/src/NetworkManager.cpp @@ -10,6 +10,10 @@ #include "esp_mac.h" #include "netdb.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +extern "C" esp_err_t esp_hosted_init(void *); +#endif + NetworkManager::NetworkManager() {} NetworkInterface *getNetifByID(Network_Interface_ID id); @@ -18,6 +22,9 @@ bool NetworkManager::begin() { static bool initialized = false; if (!initialized) { initialized = true; +#if CONFIG_ESP_WIFI_REMOTE_ENABLED + esp_hosted_init(NULL); +#endif #if CONFIG_IDF_TARGET_ESP32 uint8_t mac[8]; if (esp_efuse_mac_get_default(mac) == ESP_OK) { diff --git a/libraries/WiFi/src/AP.cpp b/libraries/WiFi/src/AP.cpp index a61be662495..9cba6e90f10 100644 --- a/libraries/WiFi/src/AP.cpp +++ b/libraries/WiFi/src/AP.cpp @@ -7,7 +7,7 @@ #include "WiFi.h" #include "WiFiGeneric.h" #include "WiFiAP.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include #include #include diff --git a/libraries/WiFi/src/STA.cpp b/libraries/WiFi/src/STA.cpp index 443d2621957..004ce161058 100644 --- a/libraries/WiFi/src/STA.cpp +++ b/libraries/WiFi/src/STA.cpp @@ -6,7 +6,7 @@ #include "WiFi.h" #include "WiFiGeneric.h" #include "WiFiSTA.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include #include #include diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp index a854cb0ceb7..7fb0ed16459 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -22,7 +22,7 @@ */ #include "WiFi.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED extern "C" { #include diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h index a823dabd864..ea2efd97697 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -22,7 +22,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#include "sdkconfig.h" +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include diff --git a/libraries/WiFi/src/WiFiAP.cpp b/libraries/WiFi/src/WiFiAP.cpp index fac84dc8512..7282daac995 100644 --- a/libraries/WiFi/src/WiFiAP.cpp +++ b/libraries/WiFi/src/WiFiAP.cpp @@ -25,7 +25,7 @@ #include "WiFi.h" #include "WiFiGeneric.h" #include "WiFiAP.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include #include diff --git a/libraries/WiFi/src/WiFiAP.h b/libraries/WiFi/src/WiFiAP.h index 9acd124c27e..4573e92ecf0 100644 --- a/libraries/WiFi/src/WiFiAP.h +++ b/libraries/WiFi/src/WiFiAP.h @@ -23,7 +23,7 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include "esp_wifi_types.h" #include "WiFiType.h" diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index ccc9518132b..d096c2e3d6e 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -24,7 +24,7 @@ #include "WiFi.h" #include "WiFiGeneric.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED extern "C" { #include @@ -39,7 +39,9 @@ extern "C" { #include #include #include +#if SOC_WIFI_SUPPORTED #include +#endif #include "lwip/ip_addr.h" #include "lwip/opt.h" #include "lwip/err.h" @@ -103,6 +105,7 @@ static void _arduino_event_cb(void *arg, esp_event_base_t event_base, int32_t ev arduino_event.event_id = ARDUINO_EVENT_WIFI_FTM_REPORT; memcpy(&arduino_event.event_info.wifi_ftm_report, event_data, sizeof(wifi_event_ftm_report_t)); +#if !CONFIG_ESP_WIFI_REMOTE_ENABLED /* * SMART CONFIG * */ @@ -157,6 +160,7 @@ static void _arduino_event_cb(void *arg, esp_event_base_t event_base, int32_t ev } else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_WIFI_CRED_SUCCESS) { log_v("Provisioning Success!"); arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_SUCCESS; +#endif } if (arduino_event.event_id < ARDUINO_EVENT_MAX) { @@ -170,6 +174,7 @@ static bool initWiFiEvents() { return false; } +#if !CONFIG_ESP_WIFI_REMOTE_ENABLED if (esp_event_handler_instance_register(SC_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb, NULL, NULL)) { log_e("event_handler_instance_register for SC_EVENT Failed!"); return false; @@ -179,6 +184,7 @@ static bool initWiFiEvents() { log_e("event_handler_instance_register for NETWORK_PROV_EVENT Failed!"); return false; } +#endif return true; } @@ -189,6 +195,7 @@ static bool deinitWiFiEvents() { return false; } +#if !CONFIG_ESP_WIFI_REMOTE_ENABLED if (esp_event_handler_unregister(SC_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb)) { log_e("esp_event_handler_unregister for SC_EVENT Failed!"); return false; @@ -198,6 +205,7 @@ static bool deinitWiFiEvents() { log_e("esp_event_handler_unregister for NETWORK_PROV_EVENT Failed!"); return false; } +#endif return true; } @@ -370,6 +378,7 @@ void WiFiGenericClass::_eventCallback(arduino_event_t *event) { // log_d("Arduino Event: %d - %s", event->event_id, WiFi.eventName(event->event_id)); if (event->event_id == ARDUINO_EVENT_WIFI_SCAN_DONE) { WiFiScanClass::_scanDone(); +#if !CONFIG_ESP_WIFI_REMOTE_ENABLED } else if (event->event_id == ARDUINO_EVENT_SC_GOT_SSID_PSWD) { WiFi.begin( (const char *)event->event_info.sc_got_ssid_pswd.ssid, (const char *)event->event_info.sc_got_ssid_pswd.password, 0, @@ -378,6 +387,7 @@ void WiFiGenericClass::_eventCallback(arduino_event_t *event) { } else if (event->event_id == ARDUINO_EVENT_SC_SEND_ACK_DONE) { esp_smartconfig_stop(); WiFiSTAClass::_smartConfigDone = true; +#endif } } @@ -693,6 +703,7 @@ bool WiFiGenericClass::initiateFTM(uint8_t frm_count, uint16_t burst_period, uin * @return true on success */ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2, wifi_rx_ant_t rx_mode, wifi_tx_ant_t tx_mode) { +#if !CONFIG_ESP_WIFI_REMOTE_ENABLED esp_phy_ant_gpio_config_t wifi_ant_io; @@ -759,7 +770,7 @@ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2 log_e("Failed to set antenna configuration"); return false; } - +#endif return true; } diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h index 2a5ca812999..fe929236a4b 100644 --- a/libraries/WiFi/src/WiFiGeneric.h +++ b/libraries/WiFi/src/WiFiGeneric.h @@ -23,7 +23,7 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include "esp_err.h" #include "esp_event.h" diff --git a/libraries/WiFi/src/WiFiMulti.cpp b/libraries/WiFi/src/WiFiMulti.cpp index a438919f792..f99ce185252 100644 --- a/libraries/WiFi/src/WiFiMulti.cpp +++ b/libraries/WiFi/src/WiFiMulti.cpp @@ -24,7 +24,7 @@ */ #include "WiFiMulti.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include #include #include diff --git a/libraries/WiFi/src/WiFiMulti.h b/libraries/WiFi/src/WiFiMulti.h index 1e11ff13f51..bda053b32d2 100644 --- a/libraries/WiFi/src/WiFiMulti.h +++ b/libraries/WiFi/src/WiFiMulti.h @@ -26,7 +26,7 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include "WiFi.h" #include diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp index 1c1ce42c12f..18c8b7207a4 100644 --- a/libraries/WiFi/src/WiFiSTA.cpp +++ b/libraries/WiFi/src/WiFiSTA.cpp @@ -25,7 +25,7 @@ #include "WiFi.h" #include "WiFiGeneric.h" #include "WiFiSTA.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include #include diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index 2c046c4c4b9..b3176ed17ca 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -23,7 +23,7 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include "WiFiType.h" #include "WiFiGeneric.h" diff --git a/libraries/WiFi/src/WiFiScan.cpp b/libraries/WiFi/src/WiFiScan.cpp index ffacc57f093..27d9edcc70c 100644 --- a/libraries/WiFi/src/WiFiScan.cpp +++ b/libraries/WiFi/src/WiFiScan.cpp @@ -25,7 +25,7 @@ #include "WiFi.h" #include "WiFiGeneric.h" #include "WiFiScan.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED extern "C" { #include diff --git a/libraries/WiFi/src/WiFiScan.h b/libraries/WiFi/src/WiFiScan.h index 0648885292f..5e1097f3ae2 100644 --- a/libraries/WiFi/src/WiFiScan.h +++ b/libraries/WiFi/src/WiFiScan.h @@ -23,7 +23,7 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include "WiFiType.h" #include "WiFiGeneric.h" diff --git a/libraries/WiFi/src/WiFiType.h b/libraries/WiFi/src/WiFiType.h index 1d721d33963..83eed72f4cb 100644 --- a/libraries/WiFi/src/WiFiType.h +++ b/libraries/WiFi/src/WiFiType.h @@ -22,7 +22,7 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include "esp_wifi_types.h" From f8e03cfaac337731ffaad0a7af0d45e91adab1a4 Mon Sep 17 00:00:00 2001 From: Mahesh Tupe Date: Tue, 15 Oct 2024 20:36:20 +0530 Subject: [PATCH 058/406] Update esp-insights version (#10456) --- idf_component.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idf_component.yml b/idf_component.yml index 9c06ef0fb72..abacb442ef2 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -72,7 +72,7 @@ dependencies: rules: - if: "target != esp32c2" espressif/esp_insights: - version: "^1.0.1" + version: "^1.2.1" rules: - if: "target != esp32c2" espressif/qrcode: From c6bf1b48160935c789b84b64f71bd1da4b8c2ee3 Mon Sep 17 00:00:00 2001 From: Mahesh Tupe Date: Tue, 15 Oct 2024 20:36:20 +0530 Subject: [PATCH 059/406] Update esp-insights version (#10456) --- idf_component.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idf_component.yml b/idf_component.yml index 5570f5d47a5..d1772d0ddb9 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -74,7 +74,7 @@ dependencies: rules: - if: "target not in [esp32c2, esp32p4]" espressif/esp_insights: - version: "^1.0.1" + version: "^1.2.1" rules: - if: "target not in [esp32c2, esp32p4]" espressif/qrcode: From a3f2568a198cac05a0c784856ba6b99e202ce2a9 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 15 Oct 2024 20:20:04 +0300 Subject: [PATCH 060/406] IDF release/v5.3 (#10465) * fix(usb): Update tinyusb init call * Update esp-insights version (#10456) * Add support for WiFi to ESP32-P4 (#10463) * feat(p4): Add support for WiFi to ESP32-P4 Implements support for external MCU connected through SDIO * fix(p4): Init SDIO host properly on Network boot esp-hosted has one function marked as "constructor" that did not run in the boot phase of the chip. This calls the function when network is started * Fix RainMaker dependent versions because Matter requires Insights 1.0.1 * IDF release/v5.3 707d097b * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: Mahesh Tupe Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- cores/esp32/esp32-hal-tinyusb.c | 19 +++++++------- idf_component.yml | 27 ++++++++++++++----- package/package_esp32_index.template.json | 32 +++++++++++------------ 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index c69fca08fc7..eca7e5d176c 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -174,9 +174,9 @@ void deinit_usb_hal() { esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) { init_usb_hal(config->external_phy); #if CONFIG_IDF_TARGET_ESP32P4 - if (!tud_init(1)) { + if (!tusb_init(1, TUSB_ROLE_DEVICE)) { #else - if (!tud_init(0)) { + if (!tusb_init(0, TUSB_ROLE_DEVICE)) { #endif log_e("Can't initialize the TinyUSB stack."); return ESP_FAIL; @@ -287,15 +287,14 @@ enum { VENDOR_REQUEST_MICROSOFT = 2 }; -static uint8_t const tinyusb_bos_descriptor[] = { - // total length, number of device caps - TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2), +static uint8_t const tinyusb_bos_descriptor[] = {// total length, number of device caps + TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2), - // Vendor Code, iLandingPage - TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1), + // Vendor Code, iLandingPage + TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1), - // Microsoft OS 2.0 descriptor - TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT) + // Microsoft OS 2.0 descriptor + TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT) }; /* @@ -831,7 +830,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { periph_ll_enable_clk_clear_rst(PERIPH_USB_MODULE); } #endif - + tinyusb_config_t tusb_cfg = { .external_phy = false // In the most cases you need to use a `false` value }; diff --git a/idf_component.yml b/idf_component.yml index d1772d0ddb9..12bfe66e739 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -51,8 +51,6 @@ dependencies: require: public espressif/esp_modem: version: "^1.1.0" - espressif/network_provisioning: - version: "~1.0.0" espressif/esp-zboss-lib: version: "^1.0.1" rules: @@ -65,22 +63,39 @@ dependencies: version: "^1.3.4" rules: - if: "target != esp32c2" + # RainMaker Start (Fixed versions, because Matter supports only Insights 1.0.1) + espressif/network_provisioning: + version: "1.0.2" espressif/esp_rainmaker: - version: "^1.0.0" + version: "1.5.0" rules: - if: "target not in [esp32c2, esp32p4]" espressif/rmaker_common: - version: "^1.4.6" + version: "1.4.6" rules: - if: "target not in [esp32c2, esp32p4]" espressif/esp_insights: - version: "^1.2.1" + version: "1.0.1" + rules: + - if: "target not in [esp32c2, esp32p4]" + # New version breaks esp_insights 1.0.1 + espressif/esp_diag_data_store: + version: "1.0.1" + rules: + - if: "target not in [esp32c2, esp32p4]" + espressif/esp_diagnostics: + version: "1.0.2" + rules: + - if: "target not in [esp32c2, esp32p4]" + espressif/cbor: + version: "0.6.0~1" rules: - if: "target not in [esp32c2, esp32p4]" espressif/qrcode: - version: "^0.1.0~1" + version: "0.1.0~2" rules: - if: "target not in [esp32c2, esp32p4]" + # RainMaker End espressif/esp-sr: version: "^1.4.2" rules: diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 413419a9b1c..9227a89034d 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -101,57 +101,57 @@ "host": "i686-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", - "size": "351074410" + "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", + "size": "350992761" }, { "host": "x86_64-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", - "size": "351074410" + "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", + "size": "350992761" }, { "host": "arm64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", - "size": "351074410" + "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", + "size": "350992761" }, { "host": "x86_64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", - "size": "351074410" + "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", + "size": "350992761" }, { "host": "x86_64-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", - "size": "351074410" + "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", + "size": "350992761" }, { "host": "i686-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", - "size": "351074410" + "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", + "size": "350992761" }, { "host": "aarch64-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", - "size": "351074410" + "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", + "size": "350992761" }, { "host": "arm-linux-gnueabihf", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:b4d431c8e6e9eb26c78cb187b9082055544956a4dac8e224ff884f770e5f0e5a", - "size": "351074410" + "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", + "size": "350992761" } ] }, From f706c276711dd1d19fcb3390a6c1df92657be1bf Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 15 Oct 2024 20:42:26 +0300 Subject: [PATCH 061/406] Update TinyUSB init method --- cores/esp32/esp32-hal-tinyusb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index eca7e5d176c..f83e8b61bd2 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -173,10 +173,15 @@ void deinit_usb_hal() { esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) { init_usb_hal(config->external_phy); + tusb_rhport_init_t tinit; + memset(&tinit, 0, sizeof(tusb_rhport_init_t)); + tinit.role = TUSB_ROLE_DEVICE; #if CONFIG_IDF_TARGET_ESP32P4 - if (!tusb_init(1, TUSB_ROLE_DEVICE)) { + tinit.speed = TUSB_SPEED_HIGH; + if (!tusb_init(1, &tinit)) { #else - if (!tusb_init(0, TUSB_ROLE_DEVICE)) { + tinit.speed = TUSB_SPEED_FULL; + if (!tusb_init(0, &tinit)) { #endif log_e("Can't initialize the TinyUSB stack."); return ESP_FAIL; From c676ce7dc0860056459e87eeb5a8bac8d730866d Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 15 Oct 2024 21:06:31 +0300 Subject: [PATCH 062/406] fix(p4): Move ESP-HOSTED init to WiFiGeneric @P-R-O-C-H-Y will add the configured pins to periman, so that they can not be assigned to anything else --- libraries/Network/src/NetworkManager.cpp | 7 ------ libraries/WiFi/src/WiFiGeneric.cpp | 32 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/libraries/Network/src/NetworkManager.cpp b/libraries/Network/src/NetworkManager.cpp index b429c482825..88059a60562 100644 --- a/libraries/Network/src/NetworkManager.cpp +++ b/libraries/Network/src/NetworkManager.cpp @@ -10,10 +10,6 @@ #include "esp_mac.h" #include "netdb.h" -#if CONFIG_ESP_WIFI_REMOTE_ENABLED -extern "C" esp_err_t esp_hosted_init(void *); -#endif - NetworkManager::NetworkManager() {} NetworkInterface *getNetifByID(Network_Interface_ID id); @@ -22,9 +18,6 @@ bool NetworkManager::begin() { static bool initialized = false; if (!initialized) { initialized = true; -#if CONFIG_ESP_WIFI_REMOTE_ENABLED - esp_hosted_init(NULL); -#endif #if CONFIG_IDF_TARGET_ESP32 uint8_t mac[8]; if (esp_efuse_mac_get_default(mac) == ESP_OK) { diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index d096c2e3d6e..f3b27365cb6 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -233,9 +233,41 @@ void WiFiGenericClass::useStaticBuffers(bool bufferMode) { extern "C" void phy_bbpll_en_usb(bool en); #endif +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +extern "C" esp_err_t esp_hosted_init(void *); + +static bool wifiHostedInit() { + static bool initialized = false; + if (!initialized) { + initialized = true; + if (esp_hosted_init(NULL) != ESP_OK) { + log_e("esp_hosted_init failed!"); + return false; + } + } + // Attach pins to periman here + // Slave chip model is CONFIG_IDF_SLAVE_TARGET + // CONFIG_ESP_SDIO_PIN_CMD + // CONFIG_ESP_SDIO_PIN_CLK + // CONFIG_ESP_SDIO_PIN_D0 + // CONFIG_ESP_SDIO_PIN_D1 + // CONFIG_ESP_SDIO_PIN_D2 + // CONFIG_ESP_SDIO_PIN_D3 + // CONFIG_ESP_SDIO_GPIO_RESET_SLAVE + + return true; +} +#endif + bool wifiLowLevelInit(bool persistent) { if (!lowLevelInitDone) { lowLevelInitDone = true; +#if CONFIG_ESP_WIFI_REMOTE_ENABLED + if (!wifiHostedInit()) { + lowLevelInitDone = false; + return lowLevelInitDone; + } +#endif if (!Network.begin()) { lowLevelInitDone = false; return lowLevelInitDone; From 9dea05b17f27551c26f455a9517da25b9c10ca7f Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 17 Oct 2024 02:38:25 +0300 Subject: [PATCH 063/406] IDF release/v5.3 707d097b (#10473) --- package/package_esp32_index.template.json | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 9227a89034d..89ec0cebf8e 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -101,57 +101,57 @@ "host": "i686-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", - "size": "350992761" + "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", + "size": "343593768" }, { "host": "x86_64-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", - "size": "350992761" + "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", + "size": "343593768" }, { "host": "arm64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", - "size": "350992761" + "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", + "size": "343593768" }, { "host": "x86_64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", - "size": "350992761" + "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", + "size": "343593768" }, { "host": "x86_64-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", - "size": "350992761" + "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", + "size": "343593768" }, { "host": "i686-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", - "size": "350992761" + "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", + "size": "343593768" }, { "host": "aarch64-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", - "size": "350992761" + "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", + "size": "343593768" }, { "host": "arm-linux-gnueabihf", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:8a3f8ba621b187a53635deef36e335aa72f18d15c89170a32ce401bedee946be", - "size": "350992761" + "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", + "size": "343593768" } ] }, From bda8fcb457189c82a195565c44ef3bedf60c5979 Mon Sep 17 00:00:00 2001 From: ws-hsw <81347510+H-sw123@users.noreply.github.com> Date: Thu, 17 Oct 2024 07:39:23 +0800 Subject: [PATCH 064/406] addition(3rd_party_board): Add Waveshare-S3-touch-lcd (#10434) * add waveshare_touch_lcd * waveshare_touch_lcd * waveshare_touch_lcd * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- boards.txt | 1204 +++++++++++++++++ .../pins_arduino.h | 73 + .../pins_arduino.h | 116 ++ .../pins_arduino.h | 116 ++ .../pins_arduino.h | 116 ++ .../pins_arduino.h | 116 ++ .../pins_arduino.h | 116 ++ 7 files changed, 1857 insertions(+) create mode 100644 variants/waveshare_esp32_s3_touch_lcd_4/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_43/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_43b/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_5/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_5b/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_7/pins_arduino.h diff --git a/boards.txt b/boards.txt index 42070a41a1c..b267f20cb1b 100644 --- a/boards.txt +++ b/boards.txt @@ -42395,3 +42395,1207 @@ waveshare_esp32_s3_touch_amoled_241.menu.EraseFlash.all=Enabled waveshare_esp32_s3_touch_amoled_241.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## + +waveshare_esp32_s3_touch_lcd_43.name=Waveshare ESP32-S3-Touch-LCD-4.3 +waveshare_esp32_s3_touch_lcd_43.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_43.pid.0=0x822E +waveshare_esp32_s3_touch_lcd_43.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_43.upload_port.0.pid=0x822E + +waveshare_esp32_s3_touch_lcd_43.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_43.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_43.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_43.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_43.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_43.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_lcd_43.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_43.upload.flags= +waveshare_esp32_s3_touch_lcd_43.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_43.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_43.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_43.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_43.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_43.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_43.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_43.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_43.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_43.build.core=esp32 +waveshare_esp32_s3_touch_lcd_43.build.variant=waveshare_esp32_s3_touch_lcd_43 +waveshare_esp32_s3_touch_lcd_43.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_43 + +waveshare_esp32_s3_touch_lcd_43.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_43.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_43.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_43.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_43.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_43.build.flash_size=8MB +waveshare_esp32_s3_touch_lcd_43.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_43.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_43.build.boot=qio +waveshare_esp32_s3_touch_lcd_43.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_43.build.partitions=default +waveshare_esp32_s3_touch_lcd_43.build.defines= +waveshare_esp32_s3_touch_lcd_43.build.loop_core= +waveshare_esp32_s3_touch_lcd_43.build.event_core= +waveshare_esp32_s3_touch_lcd_43.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_43.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_lcd_43.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_43.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_43.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_43.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_43.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_43.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_43.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_43.menu.FlashSize.8M=8MB (64Mb) +waveshare_esp32_s3_touch_lcd_43.menu.FlashSize.8M.build.flash_size=8MB +waveshare_esp32_s3_touch_lcd_43.menu.FlashSize.16M=16MB (128Mb) +waveshare_esp32_s3_touch_lcd_43.menu.FlashSize.16M.build.flash_size=16MB + +waveshare_esp32_s3_touch_lcd_43.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_43.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_43.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_43.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_43.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_43.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_43.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_43.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_43.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_43.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_43.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_43.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_43.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_43.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_43.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_43.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_43.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_43.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_43.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_43.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_43.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_43.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_43.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_43.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_43.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_43.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_43.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_43.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_43.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_43.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_43.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_43.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_43.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_43.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_43.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_43.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_43.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_43.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + +waveshare_esp32_s3_touch_lcd_43B.name=Waveshare ESP32-S3-Touch-LCD-4.3B +waveshare_esp32_s3_touch_lcd_43B.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_43B.pid.0=0x8231 +waveshare_esp32_s3_touch_lcd_43B.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_43B.upload_port.0.pid=0x8231 + +waveshare_esp32_s3_touch_lcd_43B.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_43B.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_43B.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_43B.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_43B.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_43B.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_lcd_43B.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_43B.upload.flags= +waveshare_esp32_s3_touch_lcd_43B.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_43B.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_43B.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_43B.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_43B.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_43B.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_43B.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_43B.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_43B.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_43B.build.core=esp32 +waveshare_esp32_s3_touch_lcd_43B.build.variant=waveshare_esp32_s3_touch_lcd_43b +waveshare_esp32_s3_touch_lcd_43B.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_43B + +waveshare_esp32_s3_touch_lcd_43B.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_43B.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_43B.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_43B.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_43B.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_43B.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_43B.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_43B.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_43B.build.boot=qio +waveshare_esp32_s3_touch_lcd_43B.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_43B.build.partitions=default +waveshare_esp32_s3_touch_lcd_43B.build.defines= +waveshare_esp32_s3_touch_lcd_43B.build.loop_core= +waveshare_esp32_s3_touch_lcd_43B.build.event_core= +waveshare_esp32_s3_touch_lcd_43B.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_43B.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_lcd_43B.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_43B.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_43B.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_43B.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_43B.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_43B.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_43B.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_43B.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_43B.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_43B.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_43B.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_43B.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_43B.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_43B.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_43B.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_43B.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_43B.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_43B.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_43B.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_43B.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_43B.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_43B.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_43B.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_43B.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_43B.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_43B.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_43B.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_43B.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_43B.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_43B.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_43B.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_43B.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_43B.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_43B.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_43B.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_43B.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_43B.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_43B.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_43B.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_43B.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_43B.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_43B.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_43B.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_43B.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_43B.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + +waveshare_esp32_s3_touch_lcd_7.name=Waveshare ESP32-S3-Touch-LCD-7 +waveshare_esp32_s3_touch_lcd_7.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_7.pid.0=0x8234 +waveshare_esp32_s3_touch_lcd_7.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_7.upload_port.0.pid=0x8234 + +waveshare_esp32_s3_touch_lcd_7.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_7.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_7.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_7.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_7.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_7.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_lcd_7.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_7.upload.flags= +waveshare_esp32_s3_touch_lcd_7.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_7.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_7.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_7.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_7.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_7.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_7.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_7.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_7.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_7.build.core=esp32 +waveshare_esp32_s3_touch_lcd_7.build.variant=waveshare_esp32_s3_touch_lcd_7 +waveshare_esp32_s3_touch_lcd_7.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_7 + +waveshare_esp32_s3_touch_lcd_7.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_7.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_7.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_7.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_7.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_7.build.flash_size=8MB +waveshare_esp32_s3_touch_lcd_7.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_7.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_7.build.boot=qio +waveshare_esp32_s3_touch_lcd_7.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_7.build.partitions=default +waveshare_esp32_s3_touch_lcd_7.build.defines= +waveshare_esp32_s3_touch_lcd_7.build.loop_core= +waveshare_esp32_s3_touch_lcd_7.build.event_core= +waveshare_esp32_s3_touch_lcd_7.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_7.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_lcd_7.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_7.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_7.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_7.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_7.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_7.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_7.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_7.menu.FlashSize.8M=8MB (64Mb) +waveshare_esp32_s3_touch_lcd_7.menu.FlashSize.8M.build.flash_size=8MB +waveshare_esp32_s3_touch_lcd_7.menu.FlashSize.16M=16MB (128Mb) +waveshare_esp32_s3_touch_lcd_7.menu.FlashSize.16M.build.flash_size=16MB + +waveshare_esp32_s3_touch_lcd_7.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_7.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_7.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_7.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_7.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_7.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_7.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_7.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_7.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_7.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_7.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_7.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_7.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_7.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_7.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_7.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_7.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_7.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_7.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_7.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_7.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_7.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_7.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_7.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_7.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_7.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_7.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_7.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_7.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_7.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_7.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_7.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_7.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_7.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_7.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_7.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_7.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_7.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + +waveshare_esp32_s3_touch_lcd_5.name=Waveshare ESP32-S3-Touch-LCD-5 +waveshare_esp32_s3_touch_lcd_5.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_5.pid.0=0x8237 +waveshare_esp32_s3_touch_lcd_5.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_5.upload_port.0.pid=0x8237 + +waveshare_esp32_s3_touch_lcd_5.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_5.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_5.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_5.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_5.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_5.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_lcd_5.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_5.upload.flags= +waveshare_esp32_s3_touch_lcd_5.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_5.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_5.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_5.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_5.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_5.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_5.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_5.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_5.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_5.build.core=esp32 +waveshare_esp32_s3_touch_lcd_5.build.variant=waveshare_esp32_s3_touch_lcd_5 +waveshare_esp32_s3_touch_lcd_5.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_5 + +waveshare_esp32_s3_touch_lcd_5.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_5.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_5.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_5.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_5.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_5.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_5.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_5.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_5.build.boot=qio +waveshare_esp32_s3_touch_lcd_5.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_5.build.partitions=default +waveshare_esp32_s3_touch_lcd_5.build.defines= +waveshare_esp32_s3_touch_lcd_5.build.loop_core= +waveshare_esp32_s3_touch_lcd_5.build.event_core= +waveshare_esp32_s3_touch_lcd_5.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_5.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_lcd_5.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_5.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_5.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_5.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_5.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_5.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_5.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_5.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_5.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_5.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_5.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_5.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_5.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_5.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_5.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_5.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_5.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_5.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_5.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_5.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_5.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_5.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_5.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_5.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_5.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_5.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_5.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_5.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_5.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_5.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_5.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_5.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_5.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_5.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_5.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_5.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_5.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_5.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_5.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_5.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_5.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_5.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_5.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_5.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_5.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + +waveshare_esp32_s3_touch_lcd_5B.name=Waveshare ESP32-S3-Touch-LCD-5B +waveshare_esp32_s3_touch_lcd_5B.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_5B.pid.0=0x823A +waveshare_esp32_s3_touch_lcd_5B.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_5B.upload_port.0.pid=0x823A + +waveshare_esp32_s3_touch_lcd_5B.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_5B.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_5B.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_5B.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_5B.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_5B.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_lcd_5B.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_5B.upload.flags= +waveshare_esp32_s3_touch_lcd_5B.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_5B.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_5B.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_5B.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_5B.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_5B.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_5B.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_5B.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_5B.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_5B.build.core=esp32 +waveshare_esp32_s3_touch_lcd_5B.build.variant=waveshare_esp32_s3_touch_lcd_5b +waveshare_esp32_s3_touch_lcd_5B.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_5B + +waveshare_esp32_s3_touch_lcd_5B.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_5B.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_5B.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_5B.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_5B.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_5B.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_5B.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_5B.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_5B.build.boot=qio +waveshare_esp32_s3_touch_lcd_5B.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_5B.build.partitions=default +waveshare_esp32_s3_touch_lcd_5B.build.defines= +waveshare_esp32_s3_touch_lcd_5B.build.loop_core= +waveshare_esp32_s3_touch_lcd_5B.build.event_core= +waveshare_esp32_s3_touch_lcd_5B.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_5B.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_lcd_5B.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_5B.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_5B.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_5B.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_5B.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_5B.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_5B.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_5B.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_5B.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_5B.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_5B.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_5B.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_5B.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_5B.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_5B.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_5B.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_5B.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_5B.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_5B.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_5B.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_5B.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_5B.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_5B.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_5B.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_5B.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_5B.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_5B.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_5B.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_5B.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_5B.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_5B.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_5B.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_5B.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_5B.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_5B.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_5B.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_5B.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_5B.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_5B.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_5B.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_5B.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_5B.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_5B.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_5B.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_5B.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + +waveshare_esp32_s3_touch_lcd_4.name=Waveshare ESP32-S3-Touch-LCD-4 +waveshare_esp32_s3_touch_lcd_4.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_4.pid.0=0x823D +waveshare_esp32_s3_touch_lcd_4.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_4.upload_port.0.pid=0x823D + +waveshare_esp32_s3_touch_lcd_4.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_4.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_4.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_4.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_4.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_4.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_lcd_4.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_4.upload.flags= +waveshare_esp32_s3_touch_lcd_4.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_4.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_4.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_4.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_4.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_4.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_4.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_4.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_4.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_4.build.core=esp32 +waveshare_esp32_s3_touch_lcd_4.build.variant=waveshare_esp32_s3_touch_lcd_4 +waveshare_esp32_s3_touch_lcd_4.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_4 + +waveshare_esp32_s3_touch_lcd_4.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_4.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_4.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_4.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_4.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_4.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_4.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_4.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_4.build.boot=qio +waveshare_esp32_s3_touch_lcd_4.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_4.build.partitions=default +waveshare_esp32_s3_touch_lcd_4.build.defines= +waveshare_esp32_s3_touch_lcd_4.build.loop_core= +waveshare_esp32_s3_touch_lcd_4.build.event_core= +waveshare_esp32_s3_touch_lcd_4.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_4.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_lcd_4.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_4.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_4.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_lcd_4.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_4.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_4.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_4.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_4.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_4.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_4.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_4.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_4.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_4.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_4.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_4.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_4.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_4.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_4.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_4.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_4.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_4.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_4.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_4.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_4.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_4.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_4.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_4.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_4.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_4.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_4.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_4.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_4.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_4.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_4.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_4.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_4.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_4.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_4.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_4.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_4.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_4.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_4.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_4.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_4.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_4.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## diff --git a/variants/waveshare_esp32_s3_touch_lcd_4/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_4/pins_arduino.h new file mode 100644 index 00000000000..f4a08ea7945 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_4/pins_arduino.h @@ -0,0 +1,73 @@ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x823D + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-4" +#define USB_SERIAL "" + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Def for I2C that shares the IMU I2C pins +static const uint8_t SDA = -1; +static const uint8_t SCL = -1; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +// Mapping based on the ESP32S3 data sheet - alternate for OUTPUT +static const uint8_t OUTPUT_IO2 = 2; +static const uint8_t OUTPUT_IO3 = 3; +static const uint8_t OUTPUT_IO17 = 17; +static const uint8_t OUTPUT_IO18 = 18; + +// Analog capable pins on the header +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; + +// GPIO capable pins on the header +static const uint8_t D0 = 7; +static const uint8_t D1 = 6; +static const uint8_t D2 = 5; +static const uint8_t D3 = 4; +static const uint8_t D4 = 3; +static const uint8_t D5 = 2; +static const uint8_t D6 = 1; +static const uint8_t D7 = 44; +static const uint8_t D8 = 43; +static const uint8_t D9 = 40; +static const uint8_t D10 = 39; +static const uint8_t D11 = 38; +static const uint8_t D12 = 37; +static const uint8_t D13 = 36; +static const uint8_t D14 = 35; +static const uint8_t D15 = 34; +static const uint8_t D16 = 33; + +// Touch input capable pins on the header +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_43/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_43/pins_arduino.h new file mode 100644 index 00000000000..9b60b50e0c1 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_43/pins_arduino.h @@ -0,0 +1,116 @@ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x822E + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-4.3" +#define USB_SERIAL "" + +// display for ST7262 +#define WS_LCD_B3 14 +#define WS_LCD_B4 38 +#define WS_LCD_B5 18 +#define WS_LCD_B6 17 +#define WS_LCD_B7 10 + +#define WS_LCD_G2 39 +#define WS_LCD_G3 0 +#define WS_LCD_G4 45 +#define WS_LCD_G5 48 +#define WS_LCD_G6 47 +#define WS_LCD_G7 21 + +#define WS_LCD_R3 1 +#define WS_LCD_R4 2 +#define WS_LCD_R5 42 +#define WS_LCD_R6 41 +#define WS_LCD_R7 40 + +#define WS_LCD_VSYNC 3 +#define WS_LCD_HSYNC 46 +#define WS_LCD_PCLK 7 +#define WS_LCD_DE 5 + +// Touch for gt911 +#define WS_TP_SDA 8 +#define WS_TP_SCL 9 +#define WS_TP_RST -1 +#define WS_TP_INT 4 + +//RS485 +#define WS_RS485_RXD 16 +#define WS_RS485_TXD 15 + +//CAN +#define WS_CAN_RXD 19 +#define WS_CAN_TXD 20 + +//Onboard CH422G IO expander +#define WS_CH422G_SDA 8 +#define WS_CH422G_SCL 9 + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Def for I2C that shares the IMU I2C pins +static const uint8_t SDA = 11; +static const uint8_t SCL = 10; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +// Mapping based on the ESP32S3 data sheet - alternate for OUTPUT +static const uint8_t OUTPUT_IO2 = 2; +static const uint8_t OUTPUT_IO3 = 3; +static const uint8_t OUTPUT_IO17 = 17; +static const uint8_t OUTPUT_IO18 = 18; + +// Analog capable pins on the header +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; + +// GPIO capable pins on the header +static const uint8_t D0 = 7; +static const uint8_t D1 = 6; +static const uint8_t D2 = 5; +static const uint8_t D3 = 4; +static const uint8_t D4 = 3; +static const uint8_t D5 = 2; +static const uint8_t D6 = 1; +static const uint8_t D7 = 44; +static const uint8_t D8 = 43; +static const uint8_t D9 = 40; +static const uint8_t D10 = 39; +static const uint8_t D11 = 38; +static const uint8_t D12 = 37; +static const uint8_t D13 = 36; +static const uint8_t D14 = 35; +static const uint8_t D15 = 34; +static const uint8_t D16 = 33; + +// Touch input capable pins on the header +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_43b/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_43b/pins_arduino.h new file mode 100644 index 00000000000..f3bcb406d4c --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_43b/pins_arduino.h @@ -0,0 +1,116 @@ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8231 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-4.3B" +#define USB_SERIAL "" + +// display for ST7262 +#define WS_LCD_B3 14 +#define WS_LCD_B4 38 +#define WS_LCD_B5 18 +#define WS_LCD_B6 17 +#define WS_LCD_B7 10 + +#define WS_LCD_G2 39 +#define WS_LCD_G3 0 +#define WS_LCD_G4 45 +#define WS_LCD_G5 48 +#define WS_LCD_G6 47 +#define WS_LCD_G7 21 + +#define WS_LCD_R3 1 +#define WS_LCD_R4 2 +#define WS_LCD_R5 42 +#define WS_LCD_R6 41 +#define WS_LCD_R7 40 + +#define WS_LCD_VSYNC 3 +#define WS_LCD_HSYNC 46 +#define WS_LCD_PCLK 7 +#define WS_LCD_DE 5 + +// Touch for gt911 +#define WS_TP_SDA 8 +#define WS_TP_SCL 9 +#define WS_TP_RST -1 +#define WS_TP_INT 4 + +//RS485 +#define WS_RS485_RXD 43 +#define WS_RS485_TXD 44 + +//CAN +#define WS_CAN_RXD 15 +#define WS_CAN_TXD 16 + +//Onboard CH422G IO expander +#define WS_CH422G_SDA 8 +#define WS_CH422G_SCL 9 + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Def for I2C that shares the IMU I2C pins +static const uint8_t SDA = 11; +static const uint8_t SCL = 10; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +// Mapping based on the ESP32S3 data sheet - alternate for OUTPUT +static const uint8_t OUTPUT_IO2 = 2; +static const uint8_t OUTPUT_IO3 = 3; +static const uint8_t OUTPUT_IO17 = 17; +static const uint8_t OUTPUT_IO18 = 18; + +// Analog capable pins on the header +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; + +// GPIO capable pins on the header +static const uint8_t D0 = 7; +static const uint8_t D1 = 6; +static const uint8_t D2 = 5; +static const uint8_t D3 = 4; +static const uint8_t D4 = 3; +static const uint8_t D5 = 2; +static const uint8_t D6 = 1; +static const uint8_t D7 = 44; +static const uint8_t D8 = 43; +static const uint8_t D9 = 40; +static const uint8_t D10 = 39; +static const uint8_t D11 = 38; +static const uint8_t D12 = 37; +static const uint8_t D13 = 36; +static const uint8_t D14 = 35; +static const uint8_t D15 = 34; +static const uint8_t D16 = 33; + +// Touch input capable pins on the header +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_5/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_5/pins_arduino.h new file mode 100644 index 00000000000..135dc0d0895 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_5/pins_arduino.h @@ -0,0 +1,116 @@ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8237 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-5" +#define USB_SERIAL "" + +// display for ST7262 +#define WS_LCD_B3 14 +#define WS_LCD_B4 38 +#define WS_LCD_B5 18 +#define WS_LCD_B6 17 +#define WS_LCD_B7 10 + +#define WS_LCD_G2 39 +#define WS_LCD_G3 0 +#define WS_LCD_G4 45 +#define WS_LCD_G5 48 +#define WS_LCD_G6 47 +#define WS_LCD_G7 21 + +#define WS_LCD_R3 1 +#define WS_LCD_R4 2 +#define WS_LCD_R5 42 +#define WS_LCD_R6 41 +#define WS_LCD_R7 40 + +#define WS_LCD_VSYNC 3 +#define WS_LCD_HSYNC 46 +#define WS_LCD_PCLK 7 +#define WS_LCD_DE 5 + +// Touch for gt911 +#define WS_TP_SDA 8 +#define WS_TP_SCL 9 +#define WS_TP_RST -1 +#define WS_TP_INT 4 + +//RS485 +#define WS_RS485_RXD 43 +#define WS_RS485_TXD 44 + +//CAN +#define WS_CAN_RXD 15 +#define WS_CAN_TXD 16 + +//Onboard CH422G IO expander +#define WS_CH422G_SDA 8 +#define WS_CH422G_SCL 9 + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Def for I2C that shares the IMU I2C pins +static const uint8_t SDA = 11; +static const uint8_t SCL = 10; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +// Mapping based on the ESP32S3 data sheet - alternate for OUTPUT +static const uint8_t OUTPUT_IO2 = 2; +static const uint8_t OUTPUT_IO3 = 3; +static const uint8_t OUTPUT_IO17 = 17; +static const uint8_t OUTPUT_IO18 = 18; + +// Analog capable pins on the header +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; + +// GPIO capable pins on the header +static const uint8_t D0 = 7; +static const uint8_t D1 = 6; +static const uint8_t D2 = 5; +static const uint8_t D3 = 4; +static const uint8_t D4 = 3; +static const uint8_t D5 = 2; +static const uint8_t D6 = 1; +static const uint8_t D7 = 44; +static const uint8_t D8 = 43; +static const uint8_t D9 = 40; +static const uint8_t D10 = 39; +static const uint8_t D11 = 38; +static const uint8_t D12 = 37; +static const uint8_t D13 = 36; +static const uint8_t D14 = 35; +static const uint8_t D15 = 34; +static const uint8_t D16 = 33; + +// Touch input capable pins on the header +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_5b/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_5b/pins_arduino.h new file mode 100644 index 00000000000..e8829608a26 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_5b/pins_arduino.h @@ -0,0 +1,116 @@ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x823A + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-5B" +#define USB_SERIAL "" + +// display for ST7262 +#define WS_LCD_B3 14 +#define WS_LCD_B4 38 +#define WS_LCD_B5 18 +#define WS_LCD_B6 17 +#define WS_LCD_B7 10 + +#define WS_LCD_G2 39 +#define WS_LCD_G3 0 +#define WS_LCD_G4 45 +#define WS_LCD_G5 48 +#define WS_LCD_G6 47 +#define WS_LCD_G7 21 + +#define WS_LCD_R3 1 +#define WS_LCD_R4 2 +#define WS_LCD_R5 42 +#define WS_LCD_R6 41 +#define WS_LCD_R7 40 + +#define WS_LCD_VSYNC 3 +#define WS_LCD_HSYNC 46 +#define WS_LCD_PCLK 7 +#define WS_LCD_DE 5 + +// Touch for gt911 +#define WS_TP_SDA 8 +#define WS_TP_SCL 9 +#define WS_TP_RST -1 +#define WS_TP_INT 4 + +//RS485 +#define WS_RS485_RXD 43 +#define WS_RS485_TXD 44 + +//CAN +#define WS_CAN_RXD 15 +#define WS_CAN_TXD 16 + +//Onboard CH422G IO expander +#define WS_CH422G_SDA 8 +#define WS_CH422G_SCL 9 + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Def for I2C that shares the IMU I2C pins +static const uint8_t SDA = 11; +static const uint8_t SCL = 10; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +// Mapping based on the ESP32S3 data sheet - alternate for OUTPUT +static const uint8_t OUTPUT_IO2 = 2; +static const uint8_t OUTPUT_IO3 = 3; +static const uint8_t OUTPUT_IO17 = 17; +static const uint8_t OUTPUT_IO18 = 18; + +// Analog capable pins on the header +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; + +// GPIO capable pins on the header +static const uint8_t D0 = 7; +static const uint8_t D1 = 6; +static const uint8_t D2 = 5; +static const uint8_t D3 = 4; +static const uint8_t D4 = 3; +static const uint8_t D5 = 2; +static const uint8_t D6 = 1; +static const uint8_t D7 = 44; +static const uint8_t D8 = 43; +static const uint8_t D9 = 40; +static const uint8_t D10 = 39; +static const uint8_t D11 = 38; +static const uint8_t D12 = 37; +static const uint8_t D13 = 36; +static const uint8_t D14 = 35; +static const uint8_t D15 = 34; +static const uint8_t D16 = 33; + +// Touch input capable pins on the header +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_7/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_7/pins_arduino.h new file mode 100644 index 00000000000..357edf78c34 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_7/pins_arduino.h @@ -0,0 +1,116 @@ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8234 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-7" +#define USB_SERIAL "" + +// display for ST7262 +#define WS_LCD_B3 14 +#define WS_LCD_B4 38 +#define WS_LCD_B5 18 +#define WS_LCD_B6 17 +#define WS_LCD_B7 10 + +#define WS_LCD_G2 39 +#define WS_LCD_G3 0 +#define WS_LCD_G4 45 +#define WS_LCD_G5 48 +#define WS_LCD_G6 47 +#define WS_LCD_G7 21 + +#define WS_LCD_R3 1 +#define WS_LCD_R4 2 +#define WS_LCD_R5 42 +#define WS_LCD_R6 41 +#define WS_LCD_R7 40 + +#define WS_LCD_VSYNC 3 +#define WS_LCD_HSYNC 46 +#define WS_LCD_PCLK 7 +#define WS_LCD_DE 5 + +// Touch for gt911 +#define WS_TP_SDA 8 +#define WS_TP_SCL 9 +#define WS_TP_RST -1 +#define WS_TP_INT 4 + +//RS485 +#define WS_RS485_RXD 16 +#define WS_RS485_TXD 15 + +//CAN +#define WS_CAN_RXD 19 +#define WS_CAN_TXD 20 + +//Onboard CH422G IO expander +#define WS_CH422G_SDA 8 +#define WS_CH422G_SCL 9 + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Def for I2C that shares the IMU I2C pins +static const uint8_t SDA = 11; +static const uint8_t SCL = 10; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +// Mapping based on the ESP32S3 data sheet - alternate for OUTPUT +static const uint8_t OUTPUT_IO2 = 2; +static const uint8_t OUTPUT_IO3 = 3; +static const uint8_t OUTPUT_IO17 = 17; +static const uint8_t OUTPUT_IO18 = 18; + +// Analog capable pins on the header +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; + +// GPIO capable pins on the header +static const uint8_t D0 = 7; +static const uint8_t D1 = 6; +static const uint8_t D2 = 5; +static const uint8_t D3 = 4; +static const uint8_t D4 = 3; +static const uint8_t D5 = 2; +static const uint8_t D6 = 1; +static const uint8_t D7 = 44; +static const uint8_t D8 = 43; +static const uint8_t D9 = 40; +static const uint8_t D10 = 39; +static const uint8_t D11 = 38; +static const uint8_t D12 = 37; +static const uint8_t D13 = 36; +static const uint8_t D14 = 35; +static const uint8_t D15 = 34; +static const uint8_t D16 = 33; + +// Touch input capable pins on the header +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; + +#endif /* Pins_Arduino_h */ From 7849a7943535bc2e093a5bbb9a70cae3b5f84597 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 17 Oct 2024 06:44:47 +0700 Subject: [PATCH 065/406] Add IOXESP32-C6 and ATD3.5-S3 board (#10471) Co-authored-by: Max <7087907+maxpromer@users.noreply.github.com> --- boards.txt | 358 +++++++++++++++++++++++++++++ variants/atd35s3/pins_arduino.h | 78 +++++++ variants/ioxesp32c6/pins_arduino.h | 35 +++ 3 files changed, 471 insertions(+) create mode 100644 variants/atd35s3/pins_arduino.h create mode 100644 variants/ioxesp32c6/pins_arduino.h diff --git a/boards.txt b/boards.txt index b267f20cb1b..4e82ba796d6 100644 --- a/boards.txt +++ b/boards.txt @@ -38494,6 +38494,8 @@ namino_bianco.menu.EraseFlash.all=Enabled namino_bianco.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +# IOXESP32, IOXESP32U + ioxesp32.name=IOXESP32 ioxesp32.bootloader.tool=esptool_py @@ -38604,6 +38606,7 @@ ioxesp32.menu.EraseFlash.all=Enabled ioxesp32.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +# IOXESP32PS ioxesp32ps.name=IOXESP32PS @@ -38715,6 +38718,178 @@ ioxesp32ps.menu.EraseFlash.all=Enabled ioxesp32ps.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +# IOXESP32-C6 + +ioxesp32c6.name=IOXESP32-C6 + +ioxesp32c6.bootloader.tool=esptool_py +ioxesp32c6.bootloader.tool.default=esptool_py + +ioxesp32c6.upload.tool=esptool_py +ioxesp32c6.upload.tool.default=esptool_py +ioxesp32c6.upload.tool.network=esp_ota + +ioxesp32c6.upload.maximum_size=1310720 +ioxesp32c6.upload.maximum_data_size=327680 +ioxesp32c6.upload.flags= +ioxesp32c6.upload.extra_flags= +ioxesp32c6.upload.use_1200bps_touch=false +ioxesp32c6.upload.wait_for_upload_port=false + +ioxesp32c6.serial.disableDTR=false +ioxesp32c6.serial.disableRTS=false + +ioxesp32c6.build.tarch=riscv32 +ioxesp32c6.build.target=esp +ioxesp32c6.build.mcu=esp32c6 +ioxesp32c6.build.core=esp32 +ioxesp32c6.build.variant=ioxesp32c6 +ioxesp32c6.build.board=ESP32C6_DEV +ioxesp32c6.build.bootloader_addr=0x0 + +ioxesp32c6.build.cdc_on_boot=0 +ioxesp32c6.build.f_cpu=160000000L +ioxesp32c6.build.flash_size=4MB +ioxesp32c6.build.flash_freq=80m +ioxesp32c6.build.flash_mode=qio +ioxesp32c6.build.boot=qio +ioxesp32c6.build.partitions=default +ioxesp32c6.build.defines= + +## IDE 2.0 Seems to not update the value +ioxesp32c6.menu.JTAGAdapter.default=Disabled +ioxesp32c6.menu.JTAGAdapter.default.build.copy_jtag_files=0 +ioxesp32c6.menu.JTAGAdapter.builtin=Integrated USB JTAG +ioxesp32c6.menu.JTAGAdapter.builtin.build.openocdscript=esp32c6-builtin.cfg +ioxesp32c6.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +ioxesp32c6.menu.JTAGAdapter.external=FTDI Adapter +ioxesp32c6.menu.JTAGAdapter.external.build.openocdscript=esp32c6-ftdi.cfg +ioxesp32c6.menu.JTAGAdapter.external.build.copy_jtag_files=1 +ioxesp32c6.menu.JTAGAdapter.bridge=ESP USB Bridge +ioxesp32c6.menu.JTAGAdapter.bridge.build.openocdscript=esp32c6-bridge.cfg +ioxesp32c6.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +ioxesp32c6.menu.CDCOnBoot.default=Disabled +ioxesp32c6.menu.CDCOnBoot.default.build.cdc_on_boot=0 +ioxesp32c6.menu.CDCOnBoot.cdc=Enabled +ioxesp32c6.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +ioxesp32c6.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +ioxesp32c6.menu.PartitionScheme.default.build.partitions=default +ioxesp32c6.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +ioxesp32c6.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +ioxesp32c6.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +ioxesp32c6.menu.PartitionScheme.minimal.build.partitions=minimal +ioxesp32c6.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +ioxesp32c6.menu.PartitionScheme.no_fs.build.partitions=no_fs +ioxesp32c6.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +ioxesp32c6.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +ioxesp32c6.menu.PartitionScheme.no_ota.build.partitions=no_ota +ioxesp32c6.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +ioxesp32c6.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +ioxesp32c6.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +ioxesp32c6.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +ioxesp32c6.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +ioxesp32c6.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +ioxesp32c6.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +ioxesp32c6.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +ioxesp32c6.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +ioxesp32c6.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +ioxesp32c6.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +ioxesp32c6.menu.PartitionScheme.huge_app.build.partitions=huge_app +ioxesp32c6.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +ioxesp32c6.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +ioxesp32c6.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +ioxesp32c6.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +ioxesp32c6.menu.PartitionScheme.rainmaker=RainMaker 4MB +ioxesp32c6.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +ioxesp32c6.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +ioxesp32c6.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +ioxesp32c6.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +ioxesp32c6.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +ioxesp32c6.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs +ioxesp32c6.menu.PartitionScheme.zigbee.build.partitions=zigbee +ioxesp32c6.menu.PartitionScheme.zigbee.upload.maximum_size=1310720 +ioxesp32c6.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +ioxesp32c6.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +ioxesp32c6.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +ioxesp32c6.menu.PartitionScheme.custom=Custom +ioxesp32c6.menu.PartitionScheme.custom.build.partitions= +ioxesp32c6.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +ioxesp32c6.menu.CPUFreq.160=160MHz (WiFi) +ioxesp32c6.menu.CPUFreq.160.build.f_cpu=160000000L +ioxesp32c6.menu.CPUFreq.120=120MHz (WiFi) +ioxesp32c6.menu.CPUFreq.120.build.f_cpu=120000000L +ioxesp32c6.menu.CPUFreq.80=80MHz (WiFi) +ioxesp32c6.menu.CPUFreq.80.build.f_cpu=80000000L +ioxesp32c6.menu.CPUFreq.40=40MHz +ioxesp32c6.menu.CPUFreq.40.build.f_cpu=40000000L +ioxesp32c6.menu.CPUFreq.20=20MHz +ioxesp32c6.menu.CPUFreq.20.build.f_cpu=20000000L +ioxesp32c6.menu.CPUFreq.10=10MHz +ioxesp32c6.menu.CPUFreq.10.build.f_cpu=10000000L + +ioxesp32c6.menu.FlashMode.qio=QIO +ioxesp32c6.menu.FlashMode.qio.build.flash_mode=dio +ioxesp32c6.menu.FlashMode.qio.build.boot=qio +ioxesp32c6.menu.FlashMode.dio=DIO +ioxesp32c6.menu.FlashMode.dio.build.flash_mode=dio +ioxesp32c6.menu.FlashMode.dio.build.boot=dio + +ioxesp32c6.menu.FlashFreq.80=80MHz +ioxesp32c6.menu.FlashFreq.80.build.flash_freq=80m +ioxesp32c6.menu.FlashFreq.40=40MHz +ioxesp32c6.menu.FlashFreq.40.build.flash_freq=40m + +ioxesp32c6.menu.UploadSpeed.921600=921600 +ioxesp32c6.menu.UploadSpeed.921600.upload.speed=921600 +ioxesp32c6.menu.UploadSpeed.115200=115200 +ioxesp32c6.menu.UploadSpeed.115200.upload.speed=115200 +ioxesp32c6.menu.UploadSpeed.256000.windows=256000 +ioxesp32c6.menu.UploadSpeed.256000.upload.speed=256000 +ioxesp32c6.menu.UploadSpeed.230400.windows.upload.speed=256000 +ioxesp32c6.menu.UploadSpeed.230400=230400 +ioxesp32c6.menu.UploadSpeed.230400.upload.speed=230400 +ioxesp32c6.menu.UploadSpeed.460800.linux=460800 +ioxesp32c6.menu.UploadSpeed.460800.macosx=460800 +ioxesp32c6.menu.UploadSpeed.460800.upload.speed=460800 +ioxesp32c6.menu.UploadSpeed.512000.windows=512000 +ioxesp32c6.menu.UploadSpeed.512000.upload.speed=512000 + +ioxesp32c6.menu.DebugLevel.none=None +ioxesp32c6.menu.DebugLevel.none.build.code_debug=0 +ioxesp32c6.menu.DebugLevel.error=Error +ioxesp32c6.menu.DebugLevel.error.build.code_debug=1 +ioxesp32c6.menu.DebugLevel.warn=Warn +ioxesp32c6.menu.DebugLevel.warn.build.code_debug=2 +ioxesp32c6.menu.DebugLevel.info=Info +ioxesp32c6.menu.DebugLevel.info.build.code_debug=3 +ioxesp32c6.menu.DebugLevel.debug=Debug +ioxesp32c6.menu.DebugLevel.debug.build.code_debug=4 +ioxesp32c6.menu.DebugLevel.verbose=Verbose +ioxesp32c6.menu.DebugLevel.verbose.build.code_debug=5 + +ioxesp32c6.menu.EraseFlash.none=Disabled +ioxesp32c6.menu.EraseFlash.none.upload.erase_cmd= +ioxesp32c6.menu.EraseFlash.all=Enabled +ioxesp32c6.menu.EraseFlash.all.upload.erase_cmd=-e + +ioxesp32c6.menu.ZigbeeMode.default=Disabled +ioxesp32c6.menu.ZigbeeMode.default.build.zigbee_mode= +ioxesp32c6.menu.ZigbeeMode.default.build.zigbee_libs= +ioxesp32c6.menu.ZigbeeMode.ed=Zigbee ED (end device) +ioxesp32c6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED +ioxesp32c6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port +ioxesp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +ioxesp32c6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +ioxesp32c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port +ioxesp32c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) +ioxesp32c6.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP +ioxesp32c6.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port + +############################################################## +# ATD1.47-S3 atd147_s3.name=ATD1.47-S3 @@ -38896,6 +39071,189 @@ atd147_s3.menu.EraseFlash.none.upload.erase_cmd= atd147_s3.menu.EraseFlash.all=Enabled atd147_s3.menu.EraseFlash.all.upload.erase_cmd=-e +############################################################## +# ATD3.5-S3 + +atd35s3.name=ATD3.5-S3 + +atd35s3.bootloader.tool=esptool_py +atd35s3.bootloader.tool.default=esptool_py + +atd35s3.upload.tool=esptool_py +atd35s3.upload.tool.default=esptool_py +atd35s3.upload.tool.network=esp_ota + +atd35s3.upload.maximum_size=1310720 +atd35s3.upload.maximum_data_size=327680 +atd35s3.upload.flags= +atd35s3.upload.extra_flags= +atd35s3.upload.use_1200bps_touch=false +atd35s3.upload.wait_for_upload_port=false + +atd35s3.serial.disableDTR=false +atd35s3.serial.disableRTS=false + +atd35s3.build.tarch=xtensa +atd35s3.build.bootloader_addr=0x0 +atd35s3.build.target=esp32s3 +atd35s3.build.mcu=esp32s3 +atd35s3.build.core=esp32 +atd35s3.build.variant=atd35s3 +atd35s3.build.board=ATD143_S3 + +atd35s3.build.usb_mode=1 +atd35s3.build.cdc_on_boot=0 +atd35s3.build.msc_on_boot=0 +atd35s3.build.dfu_on_boot=0 +atd35s3.build.f_cpu=240000000L +atd35s3.build.flash_size=8MB +atd35s3.build.flash_freq=80m +atd35s3.build.flash_mode=dio +atd35s3.build.boot=qio +atd35s3.build.boot_freq=80m +atd35s3.build.partitions=default_8MB +atd35s3.build.defines= +atd35s3.build.loop_core= +atd35s3.build.event_core= +atd35s3.build.psram_type=opi +atd35s3.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +atd35s3.menu.JTAGAdapter.default=Disabled +atd35s3.menu.JTAGAdapter.default.build.copy_jtag_files=0 +atd35s3.menu.JTAGAdapter.builtin=Integrated USB JTAG +atd35s3.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +atd35s3.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +atd35s3.menu.JTAGAdapter.external=FTDI Adapter +atd35s3.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +atd35s3.menu.JTAGAdapter.external.build.copy_jtag_files=1 +atd35s3.menu.JTAGAdapter.bridge=ESP USB Bridge +atd35s3.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +atd35s3.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +atd35s3.menu.PSRAM.disabled=Disabled +atd35s3.menu.PSRAM.disabled.build.defines= +atd35s3.menu.PSRAM.disabled.build.psram_type=opi +atd35s3.menu.PSRAM.enabled=Enable +atd35s3.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +atd35s3.menu.PSRAM.enabled.build.psram_type=opi + +atd35s3.menu.LoopCore.1=Core 1 +atd35s3.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +atd35s3.menu.LoopCore.0=Core 0 +atd35s3.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +atd35s3.menu.EventsCore.1=Core 1 +atd35s3.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +atd35s3.menu.EventsCore.0=Core 0 +atd35s3.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +atd35s3.menu.USBMode.hwcdc=Hardware CDC and JTAG +atd35s3.menu.USBMode.hwcdc.build.usb_mode=1 +atd35s3.menu.USBMode.default=USB-OTG (TinyUSB) +atd35s3.menu.USBMode.default.build.usb_mode=0 + +atd35s3.menu.CDCOnBoot.default=Disabled +atd35s3.menu.CDCOnBoot.default.build.cdc_on_boot=0 +atd35s3.menu.CDCOnBoot.cdc=Enabled +atd35s3.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +atd35s3.menu.MSCOnBoot.default=Disabled +atd35s3.menu.MSCOnBoot.default.build.msc_on_boot=0 +atd35s3.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +atd35s3.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +atd35s3.menu.DFUOnBoot.default=Disabled +atd35s3.menu.DFUOnBoot.default.build.dfu_on_boot=0 +atd35s3.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +atd35s3.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +atd35s3.menu.UploadMode.default=UART0 / Hardware CDC +atd35s3.menu.UploadMode.default.upload.use_1200bps_touch=false +atd35s3.menu.UploadMode.default.upload.wait_for_upload_port=false +atd35s3.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +atd35s3.menu.UploadMode.cdc.upload.use_1200bps_touch=true +atd35s3.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +atd35s3.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +atd35s3.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +atd35s3.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +atd35s3.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +atd35s3.menu.PartitionScheme.minimal.build.partitions=minimal +atd35s3.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +atd35s3.menu.PartitionScheme.no_ota.build.partitions=no_ota +atd35s3.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +atd35s3.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +atd35s3.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +atd35s3.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +atd35s3.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +atd35s3.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +atd35s3.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +atd35s3.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +atd35s3.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +atd35s3.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +atd35s3.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +atd35s3.menu.PartitionScheme.huge_app.build.partitions=huge_app +atd35s3.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +atd35s3.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +atd35s3.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +atd35s3.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +atd35s3.menu.PartitionScheme.rainmaker=RainMaker 4MB +atd35s3.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +atd35s3.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +atd35s3.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +atd35s3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +atd35s3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +atd35s3.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +atd35s3.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +atd35s3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 + +atd35s3.menu.CPUFreq.240=240MHz (WiFi) +atd35s3.menu.CPUFreq.240.build.f_cpu=240000000L +atd35s3.menu.CPUFreq.160=160MHz (WiFi) +atd35s3.menu.CPUFreq.160.build.f_cpu=160000000L +atd35s3.menu.CPUFreq.80=80MHz (WiFi) +atd35s3.menu.CPUFreq.80.build.f_cpu=80000000L +atd35s3.menu.CPUFreq.40=40MHz +atd35s3.menu.CPUFreq.40.build.f_cpu=40000000L +atd35s3.menu.CPUFreq.20=20MHz +atd35s3.menu.CPUFreq.20.build.f_cpu=20000000L +atd35s3.menu.CPUFreq.10=10MHz +atd35s3.menu.CPUFreq.10.build.f_cpu=10000000L + +atd35s3.menu.UploadSpeed.921600=921600 +atd35s3.menu.UploadSpeed.921600.upload.speed=921600 +atd35s3.menu.UploadSpeed.115200=115200 +atd35s3.menu.UploadSpeed.115200.upload.speed=115200 +atd35s3.menu.UploadSpeed.256000.windows=256000 +atd35s3.menu.UploadSpeed.256000.upload.speed=256000 +atd35s3.menu.UploadSpeed.230400.windows.upload.speed=256000 +atd35s3.menu.UploadSpeed.230400=230400 +atd35s3.menu.UploadSpeed.230400.upload.speed=230400 +atd35s3.menu.UploadSpeed.460800.linux=460800 +atd35s3.menu.UploadSpeed.460800.macosx=460800 +atd35s3.menu.UploadSpeed.460800.upload.speed=460800 +atd35s3.menu.UploadSpeed.512000.windows=512000 +atd35s3.menu.UploadSpeed.512000.upload.speed=512000 + +atd35s3.menu.DebugLevel.none=None +atd35s3.menu.DebugLevel.none.build.code_debug=0 +atd35s3.menu.DebugLevel.error=Error +atd35s3.menu.DebugLevel.error.build.code_debug=1 +atd35s3.menu.DebugLevel.warn=Warn +atd35s3.menu.DebugLevel.warn.build.code_debug=2 +atd35s3.menu.DebugLevel.info=Info +atd35s3.menu.DebugLevel.info.build.code_debug=3 +atd35s3.menu.DebugLevel.debug=Debug +atd35s3.menu.DebugLevel.debug.build.code_debug=4 +atd35s3.menu.DebugLevel.verbose=Verbose +atd35s3.menu.DebugLevel.verbose.build.code_debug=5 + +atd35s3.menu.EraseFlash.none=Disabled +atd35s3.menu.EraseFlash.none.upload.erase_cmd= +atd35s3.menu.EraseFlash.all=Enabled +atd35s3.menu.EraseFlash.all.upload.erase_cmd=-e + ############################################################## # ESP32-S3 PowerFeather diff --git a/variants/atd35s3/pins_arduino.h b/variants/atd35s3/pins_arduino.h new file mode 100644 index 00000000000..c973693b71c --- /dev/null +++ b/variants/atd35s3/pins_arduino.h @@ -0,0 +1,78 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define USB_VID 0x303a +#define USB_PID 0x1001 + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +static const uint8_t SS = 10; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 13; +static const uint8_t SCK = 12; + +// LCD pin +#define LCD_CS SS +#define LCD_SCK SCK +#define LCD_SDA MOSI +static const uint8_t LCD_DC = 21; +static const uint8_t LCD_RES = 14; +static const uint8_t LCD_BL = 3; + +// MicroSD Card pin +static const uint8_t SD_CS = 18; +static const uint8_t SD_CD = 17; + +static const uint8_t BTN_A = 4; +#define KEY_BUILTIN BTN_A + +static const uint8_t LED_BUILTIN = 5; + +// DAC pin +static const uint8_t DAC_DIN = 47; +static const uint8_t DAC_BCLK = 48; +static const uint8_t DAC_WS = 45; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/ioxesp32c6/pins_arduino.h b/variants/ioxesp32c6/pins_arduino.h new file mode 100644 index 00000000000..bcd20119514 --- /dev/null +++ b/variants/ioxesp32c6/pins_arduino.h @@ -0,0 +1,35 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +#define PIN_RGB_LED 8 +// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino +static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_RGB_LED; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN +// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() +#define RGB_BUILTIN LED_BUILTIN +#define RGB_BRIGHTNESS 64 + +static const uint8_t TX = 16; +static const uint8_t RX = 17; + +static const uint8_t SDA = 21; +static const uint8_t SCL = 22; + +static const uint8_t SS = 18; +static const uint8_t MOSI = 23; +static const uint8_t MISO = 20; +static const uint8_t SCK = 19; + +static const uint8_t A0 = 0; +static const uint8_t A1 = 1; +static const uint8_t A2 = 2; +static const uint8_t A3 = 3; +static const uint8_t A4 = 4; +static const uint8_t A5 = 5; +static const uint8_t A6 = 6; + +#endif /* Pins_Arduino_h */ From 51b2fb356da3a8c30b7a4809dff0db3d31362da8 Mon Sep 17 00:00:00 2001 From: Dogus Cendek Date: Thu, 17 Oct 2024 10:43:21 +0300 Subject: [PATCH 066/406] Add our new board "cezerio dev ESP32C6" (#10462) * Add cezerio dev ESP32-C6 * Modify pin number of cezerio dev ESP32C6 Modify pin number of cezerio dev ESP32C6 * Update boards.txt * Update USB_PID Update USB_PID * Update boards.txt Deleted flash and partition options related in flash size bigger than 4MB * Update pins_arduino.h * Merge manually to solve conflicts * Resolve Conflicts * Add cezerio dev ESP32-C6 * Modify pin number of cezerio dev ESP32C6 Modify pin number of cezerio dev ESP32C6 * Update boards.txt * Update USB_PID Update USB_PID * Update pins_arduino.h * Add cezerio dev ESP32C6 * Update pins_arduino.h * Update pins_arduino.h * Update pins_arduino.h --- boards.txt | 173 ++++++++++++++++++++ variants/cezerio_dev_esp32c6/pins_arduino.h | 52 ++++++ 2 files changed, 225 insertions(+) create mode 100644 variants/cezerio_dev_esp32c6/pins_arduino.h diff --git a/boards.txt b/boards.txt index 4e82ba796d6..d1813a7d22a 100644 --- a/boards.txt +++ b/boards.txt @@ -43957,3 +43957,176 @@ waveshare_esp32_s3_touch_lcd_4.menu.EraseFlash.all=Enabled waveshare_esp32_s3_touch_lcd_4.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## + +cezerio_dev_esp32c6.name=cezerio dev ESP32C6 + +cezerio_dev_esp32c6.bootloader.tool=esptool_py +cezerio_dev_esp32c6.bootloader.tool.default=esptool_py + +cezerio_dev_esp32c6.upload.tool=esptool_py +cezerio_dev_esp32c6.upload.tool.default=esptool_py +cezerio_dev_esp32c6.upload.tool.network=esp_ota + +cezerio_dev_esp32c6.upload.maximum_size=1310720 +cezerio_dev_esp32c6.upload.maximum_data_size=327680 +cezerio_dev_esp32c6.upload.flags= +cezerio_dev_esp32c6.upload.extra_flags= +cezerio_dev_esp32c6.upload.use_1200bps_touch=false +cezerio_dev_esp32c6.upload.wait_for_upload_port=false + +cezerio_dev_esp32c6.serial.disableDTR=false +cezerio_dev_esp32c6.serial.disableRTS=false + +cezerio_dev_esp32c6.build.tarch=riscv32 +cezerio_dev_esp32c6.build.target=esp +cezerio_dev_esp32c6.build.mcu=esp32c6 +cezerio_dev_esp32c6.build.core=esp32 +cezerio_dev_esp32c6.build.variant=cezerio_dev_esp32c6 +cezerio_dev_esp32c6.build.board=CEZERIO_DEV_ESP32C6 +cezerio_dev_esp32c6.build.bootloader_addr=0x0 + +cezerio_dev_esp32c6.build.cdc_on_boot=0 +cezerio_dev_esp32c6.build.f_cpu=160000000L +cezerio_dev_esp32c6.build.flash_size=4MB +cezerio_dev_esp32c6.build.flash_freq=80m +cezerio_dev_esp32c6.build.flash_mode=qio +cezerio_dev_esp32c6.build.boot=qio +cezerio_dev_esp32c6.build.partitions=default +cezerio_dev_esp32c6.build.defines= + +## IDE 2.0 Seems to not update the value +cezerio_dev_esp32c6.menu.JTAGAdapter.default=Disabled +cezerio_dev_esp32c6.menu.JTAGAdapter.default.build.copy_jtag_files=0 +cezerio_dev_esp32c6.menu.JTAGAdapter.builtin=Integrated USB JTAG +cezerio_dev_esp32c6.menu.JTAGAdapter.builtin.build.openocdscript=esp32c6-builtin.cfg +cezerio_dev_esp32c6.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +cezerio_dev_esp32c6.menu.JTAGAdapter.external=FTDI Adapter +cezerio_dev_esp32c6.menu.JTAGAdapter.external.build.openocdscript=esp32c6-ftdi.cfg +cezerio_dev_esp32c6.menu.JTAGAdapter.external.build.copy_jtag_files=1 +cezerio_dev_esp32c6.menu.JTAGAdapter.bridge=ESP USB Bridge +cezerio_dev_esp32c6.menu.JTAGAdapter.bridge.build.openocdscript=esp32c6-bridge.cfg +cezerio_dev_esp32c6.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +cezerio_dev_esp32c6.menu.CDCOnBoot.default=Enabled +cezerio_dev_esp32c6.menu.CDCOnBoot.default.build.cdc_on_boot=1 +cezerio_dev_esp32c6.menu.CDCOnBoot.cdc=Disabled +cezerio_dev_esp32c6.menu.CDCOnBoot.cdc.build.cdc_on_boot=0 + +cezerio_dev_esp32c6.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +cezerio_dev_esp32c6.menu.PartitionScheme.default.build.partitions=default +cezerio_dev_esp32c6.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +cezerio_dev_esp32c6.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +cezerio_dev_esp32c6.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +cezerio_dev_esp32c6.menu.PartitionScheme.minimal.build.partitions=minimal +cezerio_dev_esp32c6.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +cezerio_dev_esp32c6.menu.PartitionScheme.no_fs.build.partitions=no_fs +cezerio_dev_esp32c6.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +cezerio_dev_esp32c6.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +cezerio_dev_esp32c6.menu.PartitionScheme.no_ota.build.partitions=no_ota +cezerio_dev_esp32c6.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +cezerio_dev_esp32c6.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +cezerio_dev_esp32c6.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +cezerio_dev_esp32c6.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +cezerio_dev_esp32c6.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +cezerio_dev_esp32c6.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +cezerio_dev_esp32c6.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +cezerio_dev_esp32c6.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +cezerio_dev_esp32c6.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +cezerio_dev_esp32c6.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +cezerio_dev_esp32c6.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +cezerio_dev_esp32c6.menu.PartitionScheme.huge_app.build.partitions=huge_app +cezerio_dev_esp32c6.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +cezerio_dev_esp32c6.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +cezerio_dev_esp32c6.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +cezerio_dev_esp32c6.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +cezerio_dev_esp32c6.menu.PartitionScheme.rainmaker=RainMaker 4MB +cezerio_dev_esp32c6.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +cezerio_dev_esp32c6.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +cezerio_dev_esp32c6.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +cezerio_dev_esp32c6.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +cezerio_dev_esp32c6.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +cezerio_dev_esp32c6.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs +cezerio_dev_esp32c6.menu.PartitionScheme.zigbee.build.partitions=zigbee +cezerio_dev_esp32c6.menu.PartitionScheme.zigbee.upload.maximum_size=1310720 +cezerio_dev_esp32c6.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +cezerio_dev_esp32c6.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +cezerio_dev_esp32c6.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +cezerio_dev_esp32c6.menu.PartitionScheme.custom=Custom +cezerio_dev_esp32c6.menu.PartitionScheme.custom.build.partitions= +cezerio_dev_esp32c6.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +cezerio_dev_esp32c6.menu.CPUFreq.160=160MHz (WiFi) +cezerio_dev_esp32c6.menu.CPUFreq.160.build.f_cpu=160000000L +cezerio_dev_esp32c6.menu.CPUFreq.120=120MHz (WiFi) +cezerio_dev_esp32c6.menu.CPUFreq.120.build.f_cpu=120000000L +cezerio_dev_esp32c6.menu.CPUFreq.80=80MHz (WiFi) +cezerio_dev_esp32c6.menu.CPUFreq.80.build.f_cpu=80000000L +cezerio_dev_esp32c6.menu.CPUFreq.40=40MHz +cezerio_dev_esp32c6.menu.CPUFreq.40.build.f_cpu=40000000L +cezerio_dev_esp32c6.menu.CPUFreq.20=20MHz +cezerio_dev_esp32c6.menu.CPUFreq.20.build.f_cpu=20000000L +cezerio_dev_esp32c6.menu.CPUFreq.10=10MHz +cezerio_dev_esp32c6.menu.CPUFreq.10.build.f_cpu=10000000L + +cezerio_dev_esp32c6.menu.FlashMode.qio=QIO +cezerio_dev_esp32c6.menu.FlashMode.qio.build.flash_mode=dio +cezerio_dev_esp32c6.menu.FlashMode.qio.build.boot=qio +cezerio_dev_esp32c6.menu.FlashMode.dio=DIO +cezerio_dev_esp32c6.menu.FlashMode.dio.build.flash_mode=dio +cezerio_dev_esp32c6.menu.FlashMode.dio.build.boot=dio + +cezerio_dev_esp32c6.menu.FlashFreq.80=80MHz +cezerio_dev_esp32c6.menu.FlashFreq.80.build.flash_freq=80m +cezerio_dev_esp32c6.menu.FlashFreq.40=40MHz +cezerio_dev_esp32c6.menu.FlashFreq.40.build.flash_freq=40m + +cezerio_dev_esp32c6.menu.FlashSize.4M=4MB (32Mb) +cezerio_dev_esp32c6.menu.FlashSize.4M.build.flash_size=4MB + +cezerio_dev_esp32c6.menu.UploadSpeed.921600=921600 +cezerio_dev_esp32c6.menu.UploadSpeed.921600.upload.speed=921600 +cezerio_dev_esp32c6.menu.UploadSpeed.115200=115200 +cezerio_dev_esp32c6.menu.UploadSpeed.115200.upload.speed=115200 +cezerio_dev_esp32c6.menu.UploadSpeed.256000.windows=256000 +cezerio_dev_esp32c6.menu.UploadSpeed.256000.upload.speed=256000 +cezerio_dev_esp32c6.menu.UploadSpeed.230400.windows.upload.speed=256000 +cezerio_dev_esp32c6.menu.UploadSpeed.230400=230400 +cezerio_dev_esp32c6.menu.UploadSpeed.230400.upload.speed=230400 +cezerio_dev_esp32c6.menu.UploadSpeed.460800.linux=460800 +cezerio_dev_esp32c6.menu.UploadSpeed.460800.macosx=460800 +cezerio_dev_esp32c6.menu.UploadSpeed.460800.upload.speed=460800 +cezerio_dev_esp32c6.menu.UploadSpeed.512000.windows=512000 +cezerio_dev_esp32c6.menu.UploadSpeed.512000.upload.speed=512000 + +cezerio_dev_esp32c6.menu.DebugLevel.none=None +cezerio_dev_esp32c6.menu.DebugLevel.none.build.code_debug=0 +cezerio_dev_esp32c6.menu.DebugLevel.error=Error +cezerio_dev_esp32c6.menu.DebugLevel.error.build.code_debug=1 +cezerio_dev_esp32c6.menu.DebugLevel.warn=Warn +cezerio_dev_esp32c6.menu.DebugLevel.warn.build.code_debug=2 +cezerio_dev_esp32c6.menu.DebugLevel.info=Info +cezerio_dev_esp32c6.menu.DebugLevel.info.build.code_debug=3 +cezerio_dev_esp32c6.menu.DebugLevel.debug=Debug +cezerio_dev_esp32c6.menu.DebugLevel.debug.build.code_debug=4 +cezerio_dev_esp32c6.menu.DebugLevel.verbose=Verbose +cezerio_dev_esp32c6.menu.DebugLevel.verbose.build.code_debug=5 + +cezerio_dev_esp32c6.menu.EraseFlash.none=Disabled +cezerio_dev_esp32c6.menu.EraseFlash.none.upload.erase_cmd= +cezerio_dev_esp32c6.menu.EraseFlash.all=Enabled +cezerio_dev_esp32c6.menu.EraseFlash.all.upload.erase_cmd=-e + +cezerio_dev_esp32c6.menu.ZigbeeMode.default=Disabled +cezerio_dev_esp32c6.menu.ZigbeeMode.default.build.zigbee_mode= +cezerio_dev_esp32c6.menu.ZigbeeMode.default.build.zigbee_libs= +cezerio_dev_esp32c6.menu.ZigbeeMode.ed=Zigbee ED (end device) +cezerio_dev_esp32c6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED +cezerio_dev_esp32c6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port +cezerio_dev_esp32c6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator) +cezerio_dev_esp32c6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +cezerio_dev_esp32c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port +cezerio_dev_esp32c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) +cezerio_dev_esp32c6.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP +cezerio_dev_esp32c6.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port + +############################################################## diff --git a/variants/cezerio_dev_esp32c6/pins_arduino.h b/variants/cezerio_dev_esp32c6/pins_arduino.h new file mode 100644 index 00000000000..3ffc59aee6f --- /dev/null +++ b/variants/cezerio_dev_esp32c6/pins_arduino.h @@ -0,0 +1,52 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +#define USB_VID 0x303A +#define USB_PID 0x1001 +#define USB_MANUFACTURER "RFtek Electronics" +#define USB_PRODUCT "cezerio dev ESP32C6" +#define USB_SERIAL "" + +#define PIN_RGB_LED 3 +// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino +static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_RGB_LED; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN +// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() +#define RGB_BUILTIN LED_BUILTIN +#define RGBLED LED_BUILTIN +#define RGB_BRIGHTNESS 64 + +static const uint8_t BUT_BUILTIN = 9; +#define BUILTIN_BUT BUT_BUILTIN // backward compatibility +#define BUT_BUILTIN BUT_BUILTIN // allow testing #ifdef BUT_BUILTIN +#define BOOT BUT_BUILTIN + +static const uint8_t TX = 16; +static const uint8_t RX = 17; + +static const uint8_t SDA = 8; +static const uint8_t SCL = 7; + +static const uint8_t SS = 14; +static const uint8_t MOSI = 22; +static const uint8_t MISO = 23; +static const uint8_t SCK = 21; + +static const uint8_t A0 = 0; +static const uint8_t A1 = 1; +static const uint8_t A2 = 2; +static const uint8_t A3 = 3; +static const uint8_t A4 = 4; +static const uint8_t A5 = 5; +static const uint8_t A6 = 6; + +static const uint8_t MATRIX = 18; + +static const uint8_t IMUSD = 8; +static const uint8_t IMUSC = 7; + +#endif /* Pins_Arduino_h */ From 955b277497b4529b685fb0193ba4f7dcc61d11c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 17 Oct 2024 09:43:47 +0200 Subject: [PATCH 067/406] fix(example): print correct fade direction (#10450) * fix(example): print correct fade direction * fix(example): Change to fade in out * fix(example): Codespell fix --- .../ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino b/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino index dc152a63ea4..7155d2791cb 100644 --- a/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino +++ b/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino @@ -21,7 +21,7 @@ #define LEDC_FADE_TIME (3000) bool fade_ended = false; // status of LED fade -bool fade_on = true; +bool fade_in = true; void ARDUINO_ISR_ATTR LED_FADE_ISR() { fade_ended = true; @@ -55,15 +55,15 @@ void loop() { Serial.println("LED fade ended"); fade_ended = false; - // Check if last fade was fade on - if (fade_on) { + // Check what fade should be started next + if (fade_in) { ledcFadeWithInterrupt(LED_PIN, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME, LED_FADE_ISR); - Serial.println("LED Fade off started."); - fade_on = false; + Serial.println("LED Fade in started."); + fade_in = false; } else { ledcFadeWithInterrupt(LED_PIN, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR); - Serial.println("LED Fade on started."); - fade_on = true; + Serial.println("LED Fade out started."); + fade_in = true; } } } From 612fc4c4bbc48d6f52725ac7d14798976650123f Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 17 Oct 2024 12:12:44 +0300 Subject: [PATCH 068/406] fix(pins): Adjust P4 SPI pins to ones that are available --- variants/esp32p4/pins_arduino.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/variants/esp32p4/pins_arduino.h b/variants/esp32p4/pins_arduino.h index caba8995222..f227de428ef 100644 --- a/variants/esp32p4/pins_arduino.h +++ b/variants/esp32p4/pins_arduino.h @@ -22,10 +22,10 @@ static const uint8_t RX = 38; static const uint8_t SDA = 7; static const uint8_t SCL = 8; -static const uint8_t SS = 10; -static const uint8_t MOSI = 11; -static const uint8_t MISO = 12; -static const uint8_t SCK = 13; +static const uint8_t SS = 27; +static const uint8_t MOSI = 46; +static const uint8_t MISO = 47; +static const uint8_t SCK = 48; static const uint8_t A0 = 16; static const uint8_t A1 = 17; From ee1bc6ba0a7a4bb59d3b1e45760acffaa9603e43 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 17 Oct 2024 14:30:48 +0300 Subject: [PATCH 069/406] Add RMII Ethernet support for ESP32-P4 (#10479) * fix(eth): Add ETH support for ESP32-P4 Also adds configuration to pins_arduino.h * fix(eth): Enable TLK110 Example on P4 * fix(eth): Fix Ethernet examples * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- boards.txt | 7 +++-- .../examples/ETH_LAN8720/ETH_LAN8720.ino | 12 ++++++-- .../examples/ETH_TLK110/ETH_TLK110.ino | 12 ++++++-- .../Ethernet/examples/ETH_TLK110/ci.json | 5 +--- .../ETH_W5500_Arduino_SPI.ino | 4 +-- .../ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino | 4 +-- libraries/Ethernet/src/ETH.cpp | 28 +++++++++++++++++-- libraries/Ethernet/src/ETH.h | 26 +++++++++++++++++ variants/esp32p4/pins_arduino.h | 14 ++++++++++ 9 files changed, 96 insertions(+), 16 deletions(-) diff --git a/boards.txt b/boards.txt index fd71c2e80c2..62d66fdc828 100644 --- a/boards.txt +++ b/boards.txt @@ -188,7 +188,10 @@ esp32p4.build.variant=esp32p4 esp32p4.build.board=ESP32P4_DEV esp32p4.build.bootloader_addr=0x2000 +esp32p4.build.usb_mode=0 esp32p4.build.cdc_on_boot=0 +esp32p4.build.msc_on_boot=0 +esp32p4.build.dfu_on_boot=0 esp32p4.build.f_cpu=360000000L esp32p4.build.flash_size=4MB esp32p4.build.flash_freq=80m @@ -216,10 +219,10 @@ esp32p4.menu.PSRAM.disabled.build.defines= esp32p4.menu.PSRAM.enabled=Enabled esp32p4.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM -esp32p4.menu.USBMode.hwcdc=Hardware CDC and JTAG -esp32p4.menu.USBMode.hwcdc.build.usb_mode=1 esp32p4.menu.USBMode.default=USB-OTG (TinyUSB) esp32p4.menu.USBMode.default.build.usb_mode=0 +esp32p4.menu.USBMode.hwcdc=Hardware CDC and JTAG +esp32p4.menu.USBMode.hwcdc.build.usb_mode=1 esp32p4.menu.CDCOnBoot.default=Disabled esp32p4.menu.CDCOnBoot.default.build.cdc_on_boot=0 diff --git a/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino b/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino index 1453df63434..59a32750bf6 100644 --- a/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino +++ b/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino @@ -5,13 +5,21 @@ // Important to be defined BEFORE including ETH.h for ETH.begin() to work. // Example RMII LAN8720 (Olimex, etc.) -#ifndef ETH_PHY_TYPE -#define ETH_PHY_TYPE ETH_PHY_LAN8720 +#ifndef ETH_PHY_MDC +#define ETH_PHY_TYPE ETH_PHY_LAN8720 +#if CONFIG_IDF_TARGET_ESP32 #define ETH_PHY_ADDR 0 #define ETH_PHY_MDC 23 #define ETH_PHY_MDIO 18 #define ETH_PHY_POWER -1 #define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN +#elif CONFIG_IDF_TARGET_ESP32P4 +#define ETH_PHY_ADDR 0 +#define ETH_PHY_MDC 31 +#define ETH_PHY_MDIO 52 +#define ETH_PHY_POWER 51 +#define ETH_CLK_MODE EMAC_CLK_EXT_IN +#endif #endif #include diff --git a/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino b/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino index 3252cd120f4..242281c3997 100644 --- a/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino +++ b/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino @@ -5,13 +5,21 @@ #include -#ifndef ETH_PHY_TYPE -#define ETH_PHY_TYPE ETH_PHY_TLK110 +#ifndef ETH_PHY_MDC +#define ETH_PHY_TYPE ETH_PHY_TLK110 +#if CONFIG_IDF_TARGET_ESP32 #define ETH_PHY_ADDR 31 #define ETH_PHY_MDC 23 #define ETH_PHY_MDIO 18 #define ETH_PHY_POWER 17 #define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN +#elif CONFIG_IDF_TARGET_ESP32P4 +#define ETH_PHY_ADDR 1 +#define ETH_PHY_MDC 31 +#define ETH_PHY_MDIO 52 +#define ETH_PHY_POWER 51 +#define ETH_CLK_MODE EMAC_CLK_EXT_IN +#endif #endif static bool eth_connected = false; diff --git a/libraries/Ethernet/examples/ETH_TLK110/ci.json b/libraries/Ethernet/examples/ETH_TLK110/ci.json index 0eab13b8841..dcdfd06db51 100644 --- a/libraries/Ethernet/examples/ETH_TLK110/ci.json +++ b/libraries/Ethernet/examples/ETH_TLK110/ci.json @@ -1,8 +1,5 @@ { "requires": [ "CONFIG_ETH_USE_ESP32_EMAC=y" - ], - "targets": { - "esp32p4": false - } + ] } diff --git a/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino b/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino index d4bc78a1c07..d5d57333a55 100644 --- a/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino +++ b/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino @@ -9,7 +9,7 @@ // Set this to 1 to enable dual Ethernet support #define USE_TWO_ETH_PORTS 0 -#ifndef ETH_PHY_TYPE +#ifndef ETH_PHY_CS #define ETH_PHY_TYPE ETH_PHY_W5500 #define ETH_PHY_ADDR 1 #define ETH_PHY_CS 15 @@ -24,7 +24,7 @@ #if USE_TWO_ETH_PORTS // Second port on shared SPI bus -#ifndef ETH1_PHY_TYPE +#ifndef ETH1_PHY_CS #define ETH1_PHY_TYPE ETH_PHY_W5500 #define ETH1_PHY_ADDR 1 #define ETH1_PHY_CS 32 diff --git a/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino b/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino index 512bb78ff5e..dad54a745b7 100644 --- a/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino +++ b/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino @@ -8,7 +8,7 @@ // Set this to 1 to enable dual Ethernet support #define USE_TWO_ETH_PORTS 0 -#ifndef ETH_PHY_TYPE +#ifndef ETH_PHY_CS #define ETH_PHY_TYPE ETH_PHY_W5500 #define ETH_PHY_ADDR 1 #define ETH_PHY_CS 15 @@ -22,7 +22,7 @@ #if USE_TWO_ETH_PORTS // Second port on shared SPI bus -#ifndef ETH1_PHY_TYPE +#ifndef ETH1_PHY_CS #define ETH1_PHY_TYPE ETH_PHY_W5500 #define ETH1_PHY_ADDR 1 #define ETH1_PHY_CS 32 diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index 13f9c11f7fe..4ef184ac97a 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -148,7 +148,27 @@ void ETHClass::setTaskStackSize(size_t size) { _task_stack_size = size; } -#if (CONFIG_ETH_USE_ESP32_EMAC && !defined(CONFIG_IDF_TARGET_ESP32P4)) +#if CONFIG_ETH_USE_ESP32_EMAC +#if CONFIG_IDF_TARGET_ESP32 +#define ETH_EMAC_DEFAULT_CONFIG() ETH_ESP32_EMAC_DEFAULT_CONFIG() +#elif CONFIG_IDF_TARGET_ESP32P4 +#define ETH_EMAC_DEFAULT_CONFIG() \ + { \ + .smi_gpio = {.mdc_num = 31, .mdio_num = 52}, .interface = EMAC_DATA_INTERFACE_RMII, \ + .clock_config = {.rmii = {.clock_mode = EMAC_CLK_EXT_IN, .clock_gpio = (emac_rmii_clock_gpio_t)ETH_RMII_CLK}}, .dma_burst_len = ETH_DMA_BURST_LEN_32, \ + .intr_priority = 0, \ + .emac_dataif_gpio = \ + {.rmii = \ + {.tx_en_num = ETH_RMII_TX_EN, \ + .txd0_num = ETH_RMII_TX0, \ + .txd1_num = ETH_RMII_TX1, \ + .crs_dv_num = ETH_RMII_CRS_DV, \ + .rxd0_num = ETH_RMII_RX0, \ + .rxd1_num = ETH_RMII_RX1_EN}}, \ + .clock_config_out_in = {.rmii = {.clock_mode = EMAC_CLK_EXT_IN, .clock_gpio = (emac_rmii_clock_gpio_t) - 1}}, \ + } +#endif + bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clock_mode) { esp_err_t ret = ESP_OK; if (_eth_index > 2) { @@ -177,12 +197,16 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i #define DEFAULT_RMII_CLK_GPIO (emac_rmii_clock_gpio_t)(CONFIG_ETH_RMII_CLK_IN_GPIO) #endif - eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); + eth_esp32_emac_config_t mac_config = ETH_EMAC_DEFAULT_CONFIG(); +#if CONFIG_IDF_TARGET_ESP32 mac_config.clock_config.rmii.clock_mode = (clock_mode) ? EMAC_CLK_OUT : EMAC_CLK_EXT_IN; mac_config.clock_config.rmii.clock_gpio = (1 == clock_mode) ? EMAC_APPL_CLK_OUT_GPIO : (2 == clock_mode) ? EMAC_CLK_OUT_GPIO : (3 == clock_mode) ? EMAC_CLK_OUT_180_GPIO : EMAC_CLK_IN_GPIO; +#elif CONFIG_IDF_TARGET_ESP32P4 + mac_config.clock_config.rmii.clock_mode = (emac_rmii_clock_mode_t)clock_mode; +#endif mac_config.smi_gpio.mdc_num = digitalPinToGPIONumber(mdc); mac_config.smi_gpio.mdio_num = digitalPinToGPIONumber(mdio); diff --git a/libraries/Ethernet/src/ETH.h b/libraries/Ethernet/src/ETH.h index 14d2d042614..10d6b504c2a 100644 --- a/libraries/Ethernet/src/ETH.h +++ b/libraries/Ethernet/src/ETH.h @@ -75,6 +75,7 @@ #if CONFIG_ETH_USE_ESP32_EMAC #define ETH_PHY_IP101 ETH_PHY_TLK110 +#if CONFIG_IDF_TARGET_ESP32 typedef enum { ETH_CLOCK_GPIO0_IN, ETH_CLOCK_GPIO0_OUT, @@ -88,6 +89,31 @@ typedef enum { #define ETH_RMII_RX0 25 #define ETH_RMII_RX1_EN 26 #define ETH_RMII_CRS_DV 27 +#elif CONFIG_IDF_TARGET_ESP32P4 +typedef emac_rmii_clock_mode_t eth_clock_mode_t; +#include "pins_arduino.h" +#ifndef ETH_RMII_TX_EN +#define ETH_RMII_TX_EN 49 +#endif +#ifndef ETH_RMII_TX0 +#define ETH_RMII_TX0 34 +#endif +#ifndef ETH_RMII_TX1 +#define ETH_RMII_TX1 35 +#endif +#ifndef ETH_RMII_RX0 +#define ETH_RMII_RX0 29 +#endif +#ifndef ETH_RMII_RX1_EN +#define ETH_RMII_RX1_EN 30 +#endif +#ifndef ETH_RMII_CRS_DV +#define ETH_RMII_CRS_DV 28 +#endif +#ifndef ETH_RMII_CLK +#define ETH_RMII_CLK 50 +#endif +#endif #endif /* CONFIG_ETH_USE_ESP32_EMAC */ #ifndef ETH_PHY_SPI_FREQ_MHZ diff --git a/variants/esp32p4/pins_arduino.h b/variants/esp32p4/pins_arduino.h index f227de428ef..980e7bdb527 100644 --- a/variants/esp32p4/pins_arduino.h +++ b/variants/esp32p4/pins_arduino.h @@ -57,4 +57,18 @@ static const uint8_t T11 = 13; static const uint8_t T12 = 14; static const uint8_t T13 = 15; +#define ETH_PHY_TYPE ETH_PHY_TLK110 +#define ETH_PHY_ADDR 1 +#define ETH_PHY_MDC 31 +#define ETH_PHY_MDIO 52 +#define ETH_PHY_POWER 51 +#define ETH_RMII_TX_EN 49 +#define ETH_RMII_TX0 34 +#define ETH_RMII_TX1 35 +#define ETH_RMII_RX0 29 +#define ETH_RMII_RX1_EN 30 +#define ETH_RMII_CRS_DV 28 +#define ETH_RMII_CLK 50 +#define ETH_CLK_MODE EMAC_CLK_EXT_IN + #endif /* Pins_Arduino_h */ From ee8931d151665ffc6bb52e3edb9509a6d8e5c401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E4=B9=9D?= <153150268+Sail-211010@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:31:46 +0800 Subject: [PATCH 070/406] Add the Waveshare ESP32-S3-Touch-LCD-1.85 board (#10477) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Delete boards.txt Delete old files * Add files via upload Add the Waveshare ESP32-S3-Touch-LCD-1.85 board * Add files via upload Add the Waveshare ESP32-S3-Touch-LCD-1.85 board * Update pins_arduino.h Modify the pin definition * Add files via upload Add the Waveshare ESP32-S3-Touch-LCD-1.85 board * Update pins_arduino.h Modify the pin definition * feat(board): Add waweshare s3 rouch lcd 185 * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: Jan Procházka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- boards.txt | 237 ++++++++++++++++++ .../pins_arduino.h | 64 +++++ 2 files changed, 301 insertions(+) create mode 100644 variants/waveshare_esp32_s3_touch_lcd_185/pins_arduino.h diff --git a/boards.txt b/boards.txt index d1813a7d22a..74d709ec1e1 100644 --- a/boards.txt +++ b/boards.txt @@ -43958,6 +43958,243 @@ waveshare_esp32_s3_touch_lcd_4.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +waveshare_esp32_s3_touch_lcd_185.name=Waveshare ESP32-S3-Touch-LCD-1.85 +waveshare_esp32_s3_touch_lcd_185.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_185.pid.0=0x8290 +waveshare_esp32_s3_touch_lcd_185.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_185.upload_port.0.pid=0x8290 + +waveshare_esp32_s3_touch_lcd_185.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_185.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_185.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_185.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_185.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_185.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_185.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_185.upload.flags= +waveshare_esp32_s3_touch_lcd_185.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_185.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_185.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_185.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_185.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_185.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_185.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_185.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_185.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_185.build.core=esp32 +waveshare_esp32_s3_touch_lcd_185.build.variant=waveshare_esp32_s3_touch_lcd_185 +waveshare_esp32_s3_touch_lcd_185.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_185 + +waveshare_esp32_s3_touch_lcd_185.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_185.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_185.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_185.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_185.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_185.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_185.build.flash_freq=120m +waveshare_esp32_s3_touch_lcd_185.build.flash_mode=qio +waveshare_esp32_s3_touch_lcd_185.build.boot=qio +waveshare_esp32_s3_touch_lcd_185.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_185.build.partitions=default +waveshare_esp32_s3_touch_lcd_185.build.defines= +waveshare_esp32_s3_touch_lcd_185.build.loop_core= +waveshare_esp32_s3_touch_lcd_185.build.event_core= +waveshare_esp32_s3_touch_lcd_185.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_185.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_touch_lcd_185.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_touch_lcd_185.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_185.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_185.menu.PSRAM.enabled.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_185.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_185.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_185.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_185.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_185.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_185.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_185.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_185.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_185.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_185.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 +waveshare_esp32_s3_touch_lcd_185.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_185.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 + +waveshare_esp32_s3_touch_lcd_185.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_185.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_185.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_185.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_185.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_185.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_185.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_185.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_185.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_185.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_185.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_185.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_185.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_185.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_185.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_185.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_185.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_185.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_185.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_185.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_185.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_185.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_185.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_185.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_185.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_185.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_185.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_185.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_185.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_185.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_touch_lcd_185.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_touch_lcd_185.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_touch_lcd_185.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_touch_lcd_185.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_touch_lcd_185.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_touch_lcd_185.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## + cezerio_dev_esp32c6.name=cezerio dev ESP32C6 cezerio_dev_esp32c6.bootloader.tool=esptool_py diff --git a/variants/waveshare_esp32_s3_touch_lcd_185/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_185/pins_arduino.h new file mode 100644 index 00000000000..863590e321a --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_185/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8290 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-1.85" +#define USB_SERIAL "" + +// I2C pins +static const uint8_t SCL = 10; +static const uint8_t SDA = 11; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ From 9e48d9f2388a82d0b198f31c214b8becd0ecb204 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 17 Oct 2024 16:13:59 +0300 Subject: [PATCH 071/406] fix(spi): Fix P4 SPI Pin definitions Use GPIOs 36 or lower to avoid LDO power issues --- cores/esp32/esp32-hal-spi.c | 2 +- variants/esp32p4/pins_arduino.h | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cores/esp32/esp32-hal-spi.c b/cores/esp32/esp32-hal-spi.c index af3fd7b5f06..80928309670 100644 --- a/cores/esp32/esp32-hal-spi.c +++ b/cores/esp32/esp32-hal-spi.c @@ -65,7 +65,7 @@ #endif struct spi_struct_t { - spi_dev_t *dev; + volatile spi_dev_t *dev; #if !CONFIG_DISABLE_HAL_LOCKS SemaphoreHandle_t lock; #endif diff --git a/variants/esp32p4/pins_arduino.h b/variants/esp32p4/pins_arduino.h index 980e7bdb527..792146f5ca2 100644 --- a/variants/esp32p4/pins_arduino.h +++ b/variants/esp32p4/pins_arduino.h @@ -22,10 +22,11 @@ static const uint8_t RX = 38; static const uint8_t SDA = 7; static const uint8_t SCL = 8; -static const uint8_t SS = 27; -static const uint8_t MOSI = 46; -static const uint8_t MISO = 47; -static const uint8_t SCK = 48; +// Use GPIOs 36 or lower on the P4 DevKit to avoid LDO power issues with high numbered GPIOs. +static const uint8_t SS = 26; +static const uint8_t MOSI = 32; +static const uint8_t MISO = 33; +static const uint8_t SCK = 36; static const uint8_t A0 = 16; static const uint8_t A1 = 17; From 8570b3d270470c6ff6582aca75a1d9df95364828 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:21:08 -0300 Subject: [PATCH 072/406] Fix formatting in ETH and USB --- libraries/Ethernet/src/ETH.cpp | 44 +++++++++++++++++++++++----------- libraries/USB/src/USBHID.cpp | 4 +++- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index 4ef184ac97a..e04174fd490 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -152,22 +152,38 @@ void ETHClass::setTaskStackSize(size_t size) { #if CONFIG_IDF_TARGET_ESP32 #define ETH_EMAC_DEFAULT_CONFIG() ETH_ESP32_EMAC_DEFAULT_CONFIG() #elif CONFIG_IDF_TARGET_ESP32P4 -#define ETH_EMAC_DEFAULT_CONFIG() \ - { \ - .smi_gpio = {.mdc_num = 31, .mdio_num = 52}, .interface = EMAC_DATA_INTERFACE_RMII, \ - .clock_config = {.rmii = {.clock_mode = EMAC_CLK_EXT_IN, .clock_gpio = (emac_rmii_clock_gpio_t)ETH_RMII_CLK}}, .dma_burst_len = ETH_DMA_BURST_LEN_32, \ - .intr_priority = 0, \ - .emac_dataif_gpio = \ - {.rmii = \ - {.tx_en_num = ETH_RMII_TX_EN, \ - .txd0_num = ETH_RMII_TX0, \ - .txd1_num = ETH_RMII_TX1, \ - .crs_dv_num = ETH_RMII_CRS_DV, \ - .rxd0_num = ETH_RMII_RX0, \ - .rxd1_num = ETH_RMII_RX1_EN}}, \ - .clock_config_out_in = {.rmii = {.clock_mode = EMAC_CLK_EXT_IN, .clock_gpio = (emac_rmii_clock_gpio_t) - 1}}, \ +// clang-format off +#define ETH_EMAC_DEFAULT_CONFIG() \ + { \ + .smi_gpio = {.mdc_num = 31, .mdio_num = 52}, \ + .interface = EMAC_DATA_INTERFACE_RMII, \ + .clock_config = { \ + .rmii = { \ + .clock_mode = EMAC_CLK_EXT_IN, \ + .clock_gpio = (emac_rmii_clock_gpio_t)ETH_RMII_CLK \ + } \ + }, \ + .dma_burst_len = ETH_DMA_BURST_LEN_32, \ + .intr_priority = 0, \ + .emac_dataif_gpio = { \ + .rmii = { \ + .tx_en_num = ETH_RMII_TX_EN, \ + .txd0_num = ETH_RMII_TX0, \ + .txd1_num = ETH_RMII_TX1, \ + .crs_dv_num = ETH_RMII_CRS_DV, \ + .rxd0_num = ETH_RMII_RX0, \ + .rxd1_num = ETH_RMII_RX1_EN \ + } \ + }, \ + .clock_config_out_in = { \ + .rmii = { \ + .clock_mode = EMAC_CLK_EXT_IN, \ + .clock_gpio = (emac_rmii_clock_gpio_t) - 1 \ + } \ + }, \ } #endif +// clang-format on bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clock_mode) { esp_err_t ret = ESP_OK; diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index 4bc555b8e30..1d5d86fb3a3 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -206,7 +206,9 @@ extern "C" uint16_t tusb_hid_load_descriptor(uint8_t *dst, uint8_t *itf) { uint8_t descriptor[TUD_HID_INOUT_DESC_LEN] = { // HID Input & Output descriptor // Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval - TUD_HID_INOUT_DESCRIPTOR(*itf, str_index, tinyusb_interface_protocol, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE, 1) + TUD_HID_INOUT_DESCRIPTOR( + *itf, str_index, tinyusb_interface_protocol, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE, 1 + ) }; *itf += 1; memcpy(dst, descriptor, TUD_HID_INOUT_DESC_LEN); From edb4ee13d24688d50d2dd6b3979dac6d981f0d53 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 17 Oct 2024 19:46:14 +0300 Subject: [PATCH 073/406] IDF release/v5.3 707d097b (#10480) --- package/package_esp32_index.template.json | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 89ec0cebf8e..dc32ddae953 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -101,57 +101,57 @@ "host": "i686-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", - "size": "343593768" + "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", + "size": "343601720" }, { "host": "x86_64-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", - "size": "343593768" + "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", + "size": "343601720" }, { "host": "arm64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", - "size": "343593768" + "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", + "size": "343601720" }, { "host": "x86_64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", - "size": "343593768" + "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", + "size": "343601720" }, { "host": "x86_64-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", - "size": "343593768" + "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", + "size": "343601720" }, { "host": "i686-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", - "size": "343593768" + "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", + "size": "343601720" }, { "host": "aarch64-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", - "size": "343593768" + "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", + "size": "343601720" }, { "host": "arm-linux-gnueabihf", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:c75625cbb80f0f9ea437840c7ee00d937e4443af6903b6903bfe98928e36618e", - "size": "343593768" + "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", + "size": "343601720" } ] }, From 064d1c4d972f82c936ce05db22b69ecfc928fcab Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:29:14 -0300 Subject: [PATCH 074/406] fix(build): Fix sdkconfig copy for Arduino CLI (#10484) --- platform.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform.txt b/platform.txt index a1574e2f776..d1c3fb3a3dd 100644 --- a/platform.txt +++ b/platform.txt @@ -144,8 +144,8 @@ recipe.hooks.core.prebuild.1.pattern.windows=cmd /c echo "-DARDUINO_CORE_BUILD" recipe.hooks.core.postbuild.1.pattern.windows=cmd /c type nul > "{file_opts.path}" # Copy sdkconfig to build folder -recipe.hooks.prebuild.8.pattern=/usr/bin/env bash -c "cp -f "{runtime.platform.path}"/tools/esp32-arduino-libs/{build.mcu}/sdkconfig "{build.path}"/sdkconfig" -recipe.hooks.prebuild.8.pattern.windows=cmd /c COPY /y "{runtime.platform.path}\tools\esp32-arduino-libs\{build.mcu}\sdkconfig" "{build.path}\sdkconfig" +recipe.hooks.prebuild.8.pattern=/usr/bin/env bash -c "cp -f "{compiler.sdk.path}"/sdkconfig "{build.path}"/sdkconfig" +recipe.hooks.prebuild.8.pattern.windows=cmd /c COPY /y "{compiler.sdk.path}\sdkconfig" "{build.path}\sdkconfig" ## Compile c files recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.extra_flags} {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" -DARDUINO_VARIANT="{build.variant}" -DARDUINO_PARTITION_{build.partitions} {build.extra_flags} {compiler.cpreprocessor.flags} {includes} "@{build.opt.path}" "@{file_opts.path}" "{source_file}" -o "{object_file}" From 4ca635a3b6234a5dca5dfc3f44647235666b431d Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Sat, 19 Oct 2024 06:00:48 -0300 Subject: [PATCH 075/406] ci(json): Add requires_any field and use QIO by default to match IDE (#10472) * ci(FQBN): Use QIO as default as DIO can be used on demand now * fix(indentation): Fix default indentation for bash files * fix(compilation): Make errors appear on CI fail * ci(json): Add requires_any field to JSON and fix comparison --- .editorconfig | 2 +- .github/scripts/install-platformio-esp32.sh | 42 +++++++++-- .github/scripts/sketch_utils.sh | 79 ++++++++++++++++----- .github/scripts/tests_run.sh | 23 +++++- docs/en/contributing.rst | 16 +++-- 5 files changed, 130 insertions(+), 32 deletions(-) diff --git a/.editorconfig b/.editorconfig index eda8544321b..e22936cb1fe 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,7 +18,7 @@ indent_size = 2 indent_style = space [*.{bash,sh}] -indent_size = 2 +indent_size = 4 indent_style = space [*.{c,cc,cp,cpp,cxx,h,hh,hpp,hxx,ii,inl,ino,ixx,pde,tpl,tpp,txx}] diff --git a/.github/scripts/install-platformio-esp32.sh b/.github/scripts/install-platformio-esp32.sh index a9aab496e19..5091ea69353 100755 --- a/.github/scripts/install-platformio-esp32.sh +++ b/.github/scripts/install-platformio-esp32.sh @@ -96,9 +96,9 @@ function count_sketches(){ # count_sketches continue fi - # Check if the sketch requires any configuration options + # Check if the sketch requires any configuration options (AND) requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) - if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + if [[ "$requirements" != "null" && "$requirements" != "" ]]; then for requirement in $requirements; do requirement=$(echo $requirement | xargs) found_line=$(grep -E "^$requirement" "$SDKCONFIG_DIR/esp32/sdkconfig") @@ -107,6 +107,23 @@ function count_sketches(){ # count_sketches fi done fi + + # Check if the sketch requires any configuration options (OR) + requirements_or=$(jq -r '.requires_any[]? // empty' $sketchdir/ci.json) + if [[ "$requirements_or" != "null" && "$requirements_or" != "" ]]; then + found=false + for requirement in $requirements_or; do + requirement=$(echo $requirement | xargs) + found_line=$(grep -E "^$requirement" "$SDKCONFIG_DIR/esp32/sdkconfig") + if [[ "$found_line" != "" ]]; then + found=true + break + fi + done + if [[ "$found" == "false" ]]; then + continue + fi + fi fi echo $sketch >> sketches.txt @@ -187,9 +204,9 @@ function build_pio_sketches(){ # build_pio_sketches [ex # Default FQBN options if none were passed in the command line. - esp32_opts="PSRAM=enabled,FlashMode=dio${fqbn_append:+,$fqbn_append}" - esp32s2_opts="PSRAM=enabled,FlashMode=dio${fqbn_append:+,$fqbn_append}" - esp32s3_opts="PSRAM=opi,USBMode=default,FlashMode=dio${fqbn_append:+,$fqbn_append}" - esp32c3_opts="FlashMode=dio${fqbn_append:+,$fqbn_append}" - esp32c6_opts="FlashMode=dio${fqbn_append:+,$fqbn_append}" - esp32h2_opts="FlashMode=dio${fqbn_append:+,$fqbn_append}" + esp32_opts="PSRAM=enabled${fqbn_append:+,$fqbn_append}" + esp32s2_opts="PSRAM=enabled${fqbn_append:+,$fqbn_append}" + esp32s3_opts="PSRAM=opi,USBMode=default${fqbn_append:+,$fqbn_append}" + esp32c3_opts="$fqbn_append" + esp32c6_opts="$fqbn_append" + esp32h2_opts="$fqbn_append" # Select the common part of the FQBN based on the target. The rest will be # appended depending on the passed options. + opt="" + case "$target" in "esp32") - fqbn="espressif:esp32:esp32:${options:-$esp32_opts}" + [ -n "${options:-$esp32_opts}" ] && opt=":${options:-$esp32_opts}" + fqbn="espressif:esp32:esp32$opt" ;; "esp32s2") - fqbn="espressif:esp32:esp32s2:${options:-$esp32s2_opts}" + [ -n "${options:-$esp32s2_opts}" ] && opt=":${options:-$esp32s2_opts}" + fqbn="espressif:esp32:esp32s2$opt" ;; "esp32c3") - fqbn="espressif:esp32:esp32c3:${options:-$esp32c3_opts}" + [ -n "${options:-$esp32c3_opts}" ] && opt=":${options:-$esp32c3_opts}" + fqbn="espressif:esp32:esp32c3$opt" ;; "esp32s3") - fqbn="espressif:esp32:esp32s3:${options:-$esp32s3_opts}" + [ -n "${options:-$esp32s3_opts}" ] && opt=":${options:-$esp32s3_opts}" + fqbn="espressif:esp32:esp32s3$opt" ;; "esp32c6") - fqbn="espressif:esp32:esp32c6:${options:-$esp32c6_opts}" + [ -n "${options:-$esp32c6_opts}" ] && opt=":${options:-$esp32c6_opts}" + fqbn="espressif:esp32:esp32c6$opt" ;; "esp32h2") - fqbn="espressif:esp32:esp32h2:${options:-$esp32h2_opts}" + [ -n "${options:-$esp32h2_opts}" ] && opt=":${options:-$esp32h2_opts}" + fqbn="espressif:esp32:esp32h2$opt" ;; esac @@ -163,9 +171,9 @@ function build_sketch(){ # build_sketch [ex exit 0 fi - # Check if the sketch requires any configuration options + # Check if the sketch requires any configuration options (AND) requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) - if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + if [[ "$requirements" != "null" && "$requirements" != "" ]]; then for requirement in $requirements; do requirement=$(echo $requirement | xargs) found_line=$(grep -E "^$requirement" "$SDKCONFIG_DIR/$target/sdkconfig") @@ -175,6 +183,24 @@ function build_sketch(){ # build_sketch [ex fi done fi + + # Check if the sketch excludes any configuration options (OR) + requirements_or=$(jq -r '.requires_any[]? // empty' $sketchdir/ci.json) + if [[ "$requirements_or" != "null" && "$requirements_or" != "" ]]; then + found=false + for requirement in $requirements_or; do + requirement=$(echo $requirement | xargs) + found_line=$(grep -E "^$requirement" "$SDKCONFIG_DIR/$target/sdkconfig") + if [[ "$found_line" != "" ]]; then + found=true + break + fi + done + if [[ "$found" == "false" ]]; then + echo "Target $target meets none of the requirements in requires_any for $sketchname. Skipping." + exit 0 + fi + fi fi ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp" @@ -213,9 +239,9 @@ function build_sketch(){ # build_sketch [ex --build-cache-path "$ARDUINO_CACHE_DIR" \ --build-path "$build_dir" \ $xtra_opts "${sketchdir}" \ - > $output_file + 2>&1 | tee $output_file - exit_status=$? + exit_status=${PIPESTATUS[0]} if [ $exit_status -ne 0 ]; then echo "ERROR: Compilation failed with error code $exit_status" exit $exit_status @@ -322,9 +348,9 @@ function count_sketches(){ # count_sketches [target] [file] [ignore-requi fi if [ "$ignore_requirements" != "1" ]; then - # Check if the sketch requires any configuration options + # Check if the sketch requires any configuration options (AND) requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) - if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + if [[ "$requirements" != "null" && "$requirements" != "" ]]; then for requirement in $requirements; do requirement=$(echo $requirement | xargs) found_line=$(grep -E "^$requirement" $SDKCONFIG_DIR/$target/sdkconfig) @@ -333,6 +359,23 @@ function count_sketches(){ # count_sketches [target] [file] [ignore-requi fi done fi + + # Check if the sketch excludes any configuration options (OR) + requirements_or=$(jq -r '.requires_any[]? // empty' $sketchdir/ci.json) + if [[ "$requirements_or" != "null" && "$requirements_or" != "" ]]; then + found=false + for requirement in $requirements_or; do + requirement=$(echo $requirement | xargs) + found_line=$(grep -E "^$requirement" $SDKCONFIG_DIR/$target/sdkconfig) + if [[ "$found_line" != "" ]]; then + found=true + break + fi + done + if [[ "$found" == "false" ]]; then + continue 2 + fi + fi fi fi echo $sketch >> sketches.txt diff --git a/.github/scripts/tests_run.sh b/.github/scripts/tests_run.sh index 63ab2ca6dad..f4a9b9d6dd4 100755 --- a/.github/scripts/tests_run.sh +++ b/.github/scripts/tests_run.sh @@ -36,9 +36,9 @@ function run_test() { return 0 fi - # Check if the sketch requires any configuration options + # Check if the sketch requires any configuration options (AND) requirements=$(jq -r '.requires[]? // empty' $sketchdir/ci.json) - if [[ "$requirements" != "null" ]] || [[ "$requirements" != "" ]]; then + if [[ "$requirements" != "null" && "$requirements" != "" ]]; then for requirement in $requirements; do requirement=$(echo $requirement | xargs) found_line=$(grep -E "^$requirement" "$SDKCONFIG_PATH") @@ -49,6 +49,25 @@ function run_test() { fi done fi + + # Check if the sketch requires any configuration options (OR) + requirements_or=$(jq -r '.requires_any[]? // empty' $sketchdir/ci.json) + if [[ "$requirements_or" != "null" && "$requirements_or" != "" ]]; then + found=false + for requirement in $requirements_or; do + requirement=$(echo $requirement | xargs) + found_line=$(grep -E "^$requirement" "$SDKCONFIG_PATH") + if [[ "$found_line" != "" ]]; then + found=true + break + fi + done + if [[ "$found" == "false" ]]; then + printf "\033[93mTarget $target meets none of the requirements in requires_any for $sketchname. Skipping.\033[0m\n" + printf "\n\n\n" + return 0 + fi + fi fi if [ $len -eq 1 ]; then diff --git a/docs/en/contributing.rst b/docs/en/contributing.rst index f4ed6c34761..bc3e2e89674 100644 --- a/docs/en/contributing.rst +++ b/docs/en/contributing.rst @@ -172,12 +172,12 @@ And in the ``README.md`` file: By default, the CI system will use the FQBNs specified in the ``.github/scripts/sketch_utils.sh`` file to compile the sketches. Currently, the default FQBNs are: -* ``espressif:esp32:esp32:PSRAM=enabled,FlashMode=dio`` -* ``espressif:esp32:esp32s2:PSRAM=enabled,FlashMode=dio`` -* ``espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,FlashMode=dio`` -* ``espressif:esp32:esp32c3:FlashMode=dio`` -* ``espressif:esp32:esp32c6:FlashMode=dio`` -* ``espressif:esp32:esp32h2:FlashMode=dio`` +* ``espressif:esp32:esp32:PSRAM=enabled`` +* ``espressif:esp32:esp32s2:PSRAM=enabled`` +* ``espressif:esp32:esp32s3:PSRAM=opi,USBMode=default`` +* ``espressif:esp32:esp32c3`` +* ``espressif:esp32:esp32c6`` +* ``espressif:esp32:esp32h2`` There are two ways to alter the FQBNs used to compile the sketches: by using the ``fqbn`` or ``fqbn_append`` fields in the ``ci.json`` file. @@ -408,7 +408,9 @@ CI JSON File The ``ci.json`` file is used to specify how the test suite and sketches will handled by the CI system. It can contain the following fields: * ``requires``: A list of configurations in ``sdkconfig`` that are required to run the test suite. The test suite will only run on the targets - that have the required configurations. By default, no configurations are required. + that have **ALL** the required configurations. By default, no configurations are required. +* ``requires_any``: A list of configurations in ``sdkconfig`` that are required to run the test suite. The test suite will only run on the targets + that have **ANY** of the required configurations. By default, no configurations are required. * ``targets``: A dictionary that specifies the targets for which the tests will be run. The key is the target name and the value is a boolean that specifies if the test should be run for that target. By default, all targets are enabled as long as they have the required configurations specified in the ``requires`` field. This field is also valid for examples. From a7d9b670a8655778c08d745c061e6a6f9f223061 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Mon, 21 Oct 2024 11:56:01 +0300 Subject: [PATCH 076/406] Add missing versions to ISSUE_REPORT Versions 3.0.5 and 3.0.6 were added --- .github/ISSUE_TEMPLATE/Issue-report.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml index 17a3f7f2612..d5b756085c7 100644 --- a/.github/ISSUE_TEMPLATE/Issue-report.yml +++ b/.github/ISSUE_TEMPLATE/Issue-report.yml @@ -41,6 +41,8 @@ body: options: - latest master (checkout manually) - latest development Release Candidate (RC-X) + - v3.0.6 + - v3.0.5 - v3.0.4 - v3.0.3 - v3.0.2 From 7cfe470d8d36e2ca45783f0e9b5a80bd3268e5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:29:01 +0200 Subject: [PATCH 077/406] feat(touch): Support NG touch driver for P4 (#10448) * feat(touch): Support NG touch driver for P4 * fix(ci): Touch test + IDF compilation fixes * fix(ci): remove debug prints from touch test * fix(ci): Fix touch test for esp32 * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- CMakeLists.txt | 5 + cores/esp32/esp32-hal-touch-ng.c | 453 ++++++++++++++++++ cores/esp32/esp32-hal-touch-ng.h | 91 ++++ cores/esp32/esp32-hal-touch.c | 27 +- cores/esp32/esp32-hal-touch.h | 4 +- cores/esp32/esp32-hal.h | 1 + cores/esp32/io_pin_remap.h | 2 +- .../DeepSleep/TouchWakeUp/TouchWakeUp.ino | 8 +- .../examples/DeepSleep/TouchWakeUp/ci.json | 3 +- .../Touch/TouchInterrupt/TouchInterrupt.ino | 5 + .../examples/Touch/TouchInterrupt/ci.json | 5 +- .../ESP32/examples/Touch/TouchRead/ci.json | 5 +- tests/validation/touch/ci.json | 5 +- tests/validation/touch/touch.ino | 75 ++- 14 files changed, 643 insertions(+), 46 deletions(-) create mode 100644 cores/esp32/esp32-hal-touch-ng.c create mode 100644 cores/esp32/esp32-hal-touch-ng.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a06f815c9d8..6688a97803d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ set(CORE_SRCS cores/esp32/esp32-hal-timer.c cores/esp32/esp32-hal-tinyusb.c cores/esp32/esp32-hal-touch.c + cores/esp32/esp32-hal-touch-ng.c cores/esp32/esp32-hal-uart.c cores/esp32/esp32-hal-rmt.c cores/esp32/Esp.cpp @@ -317,6 +318,10 @@ if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_OpenThre endif() endif() +if(IDF_TARGET STREQUAL "esp32p4") + list(APPEND requires esp_driver_touch_sens) +endif() + idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires}) if(NOT CONFIG_FREERTOS_HZ EQUAL 1000 AND NOT "$ENV{ARDUINO_SKIP_TICK_CHECK}") diff --git a/cores/esp32/esp32-hal-touch-ng.c b/cores/esp32/esp32-hal-touch-ng.c new file mode 100644 index 00000000000..888a299ec0c --- /dev/null +++ b/cores/esp32/esp32-hal-touch-ng.c @@ -0,0 +1,453 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "soc/soc_caps.h" + +#if SOC_TOUCH_SENSOR_SUPPORTED +#if SOC_TOUCH_SENSOR_VERSION == 3 // ESP32P4 for now + +#include "driver/touch_sens.h" +#include "esp32-hal-touch-ng.h" +#include "esp32-hal-periman.h" + +/* + Internal Private Touch Data Structure and Functions +*/ + +typedef void (*voidFuncPtr)(void); +typedef void (*voidArgFuncPtr)(void *); + +typedef struct { + voidFuncPtr fn; + bool callWithArgs; + void *arg; + bool lastStatusIsPressed; +} TouchInterruptHandle_t; + +static TouchInterruptHandle_t __touchInterruptHandlers[SOC_TOUCH_SENSOR_NUM] = { + 0, +}; + +static uint8_t _sample_num = 1; +static uint32_t _div_num = 1; +static uint8_t _coarse_freq_tune = 1; +static uint8_t _fine_freq_tune = 1; +static uint8_t used_pads = 0; + +static uint32_t __touchSleepTime = 256; +static float __touchMeasureTime = 32.0f; + +static touch_sensor_config_t sensor_config; + +static bool initialized = false; +static bool enabled = false; +static bool running = false; +static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = {false}; + +static touch_sensor_handle_t touch_sensor_handle = NULL; +static touch_channel_handle_t touch_channel_handle[SOC_TOUCH_SENSOR_NUM] = {}; + +// Active threshold to benchmark ratio. (i.e., touch will be activated when data >= benchmark * (1 + ratio)) +static float s_thresh2bm_ratio = 0.015f; // 1.5% for all channels + +static bool ARDUINO_ISR_ATTR __touchOnActiveISR(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) { + uint8_t pad_num = (uint8_t)event->chan_id; + __touchInterruptHandlers[pad_num].lastStatusIsPressed = true; + if (__touchInterruptHandlers[pad_num].fn) { + // keeping backward compatibility with "void cb(void)" and with new "void cb(void *)" + if (__touchInterruptHandlers[pad_num].callWithArgs) { + ((voidArgFuncPtr)__touchInterruptHandlers[pad_num].fn)(__touchInterruptHandlers[pad_num].arg); + } else { + __touchInterruptHandlers[pad_num].fn(); + } + } + return false; +} + +static bool ARDUINO_ISR_ATTR __touchOnInactiveISR(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx) { + uint8_t pad_num = (uint8_t)event->chan_id; + __touchInterruptHandlers[pad_num].lastStatusIsPressed = false; + if (__touchInterruptHandlers[pad_num].fn) { + // keeping backward compatibility with "void cb(void)" and with new "void cb(void *)" + if (__touchInterruptHandlers[pad_num].callWithArgs) { + ((voidArgFuncPtr)__touchInterruptHandlers[pad_num].fn)(__touchInterruptHandlers[pad_num].arg); + } else { + __touchInterruptHandlers[pad_num].fn(); + } + } + return false; +} + +bool touchStop() { + if (!running) { // Already stopped + return true; + } + if (touch_sensor_stop_continuous_scanning(touch_sensor_handle) != ESP_OK) { + log_e("Touch sensor stop scanning failed!"); + return false; + } + running = false; + return true; +} + +bool touchDisable() { + if (!enabled) { // Already disabled + return true; + } + if (!running && (touch_sensor_disable(touch_sensor_handle) != ESP_OK)) { + log_e("Touch sensor still running or disable failed!"); + return false; + } + enabled = false; + return true; +} + +bool touchStart() { + if (running) { // Already running + return true; + } + if (enabled && (touch_sensor_start_continuous_scanning(touch_sensor_handle) != ESP_OK)) { + log_e("Touch sensor not enabled or failed to start continuous scanning failed!"); + return false; + } + running = true; + return true; +} + +bool touchEnable() { + if (enabled) { // Already enabled + return true; + } + if (touch_sensor_enable(touch_sensor_handle) != ESP_OK) { + log_e("Touch sensor enable failed!"); + return false; + } + enabled = true; + return true; +} + +bool touchBenchmarkThreshold(uint8_t pad) { + if (!touchEnable()) { + return false; + } + + /* Scan the enabled touch channels for several times, to make sure the initial channel data is stable */ + for (int i = 0; i < 3; i++) { + if (touch_sensor_trigger_oneshot_scanning(touch_sensor_handle, 2000) != ESP_OK) { + log_e("Touch sensor trigger oneshot scanning failed!"); + return false; + } + } + + /* Disable the touch channel to rollback the state */ + if (!touchDisable()) { + return false; + } + + // Reconfigure passed pad with new threshold + uint32_t benchmark[_sample_num] = {}; + if (touch_channel_read_data(touch_channel_handle[pad], TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark) != ESP_OK) { + log_e("Touch channel read data failed!"); + return false; + } + /* Calculate the proper active thresholds regarding the initial benchmark */ + touch_channel_config_t chan_cfg = {}; + for (int i = 0; i < _sample_num; i++) { + chan_cfg.active_thresh[i] = (uint32_t)(benchmark[i] * s_thresh2bm_ratio); + log_v("Configured [CH %d] sample %d: benchmark = %" PRIu32 ", threshold = %" PRIu32 "\t", pad, i, benchmark[i], chan_cfg.active_thresh[i]); + } + /* Update the channel configuration */ + if (touch_sensor_reconfig_channel(touch_channel_handle[pad], &chan_cfg) != ESP_OK) { + log_e("Touch sensor threshold reconfig channel failed!"); + return false; + } + return true; +} + +static bool touchDetachBus(void *pin) { + int8_t pad = digitalPinToTouchChannel((int)(pin - 1)); + channels_initialized[pad] = false; + //disable touch pad and delete the channel + touch_sensor_del_channel(touch_channel_handle[pad]); + used_pads--; + if (used_pads == 0) { + touchStop(); + touchDisable(); + if (touch_sensor_del_controller(touch_sensor_handle) != ESP_OK) //deinit touch module, as no pads are used + { + log_e("Touch module deinit failed!"); + return false; + } + initialized = false; + } + return true; +} + +static void __touchInit() { + if (initialized) { + return; + } + // Support only one sample configuration for now + touch_sensor_sample_config_t single_sample_cfg = TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(_div_num, _coarse_freq_tune, _fine_freq_tune); + touch_sensor_sample_config_t sample_cfg[_sample_num] = {}; + sample_cfg[0] = single_sample_cfg; + + /* Allocate new touch controller handle */ + touch_sensor_config_t sens_cfg = { + .power_on_wait_us = __touchSleepTime, + .meas_interval_us = __touchMeasureTime, + .max_meas_time_us = 0, + .output_mode = TOUCH_PAD_OUT_AS_CLOCK, + .sample_cfg_num = _sample_num, + .sample_cfg = sample_cfg, + }; + + // touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(_sample_num, sample_cfg); + if (touch_sensor_new_controller(&sens_cfg, &touch_sensor_handle) != ESP_OK) { + goto err; + } + + sensor_config = sens_cfg; + /* Configure the touch sensor filter */ + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + if (touch_sensor_config_filter(touch_sensor_handle, &filter_cfg) != ESP_OK) { + goto err; + } + + /* Register the touch sensor on_active and on_inactive callbacks */ + touch_event_callbacks_t callbacks = { + .on_active = __touchOnActiveISR, + .on_inactive = __touchOnInactiveISR, + .on_measure_done = NULL, + .on_scan_done = NULL, + .on_timeout = NULL, + .on_proximity_meas_done = NULL, + }; + if (touch_sensor_register_callbacks(touch_sensor_handle, &callbacks, NULL) != ESP_OK) { + goto err; + } + + initialized = true; + return; +err: + log_e(" Touch sensor initialization error."); + initialized = false; + return; +} + +static void __touchChannelInit(int pad) { + if (channels_initialized[pad]) { + return; + } + + // Initial setup with default Threshold + __touchInterruptHandlers[pad].fn = NULL; + + touch_channel_config_t chan_cfg = { + .active_thresh = {1000} // default threshold, will be updated after benchmark + }; + + if (!touchStop() || !touchDisable()) { + log_e("Touch sensor stop and disable failed!"); + return; + } + + if (touch_sensor_new_channel(touch_sensor_handle, pad, &chan_cfg, &touch_channel_handle[pad]) != ESP_OK) { + log_e("Touch sensor new channel failed!"); + return; + } + + // Benchmark active threshold and reconfigure pad + if (!touchBenchmarkThreshold(pad)) { + log_e("Touch sensor benchmark threshold failed!"); + return; + } + + channels_initialized[pad] = true; + used_pads++; + + if (!touchEnable() || !touchStart()) { + log_e("Touch sensor enable and start failed!"); + } +} + +static touch_value_t __touchRead(uint8_t pin) { + int8_t pad = digitalPinToTouchChannel(pin); + if (pad < 0) { + log_e(" No touch pad on selected pin!"); + return 0; + } + + if (perimanGetPinBus(pin, ESP32_BUS_TYPE_TOUCH) == NULL) { + perimanSetBusDeinit(ESP32_BUS_TYPE_TOUCH, touchDetachBus); + if (!perimanClearPinBus(pin)) { + return 0; + } + __touchInit(); + __touchChannelInit(pad); + + if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_TOUCH, (void *)(pin + 1), -1, pad)) { + touchDetachBus((void *)(pin + 1)); + return 0; + } + } + + uint32_t touch_read[_sample_num] = {}; + touch_channel_read_data(touch_channel_handle[pad], TOUCH_CHAN_DATA_TYPE_SMOOTH, touch_read); + touch_value_t touch_value = touch_read[0]; // only one sample configuration for now + + return touch_value; +} + +static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Args, bool callWithArgs, touch_value_t threshold) { + int8_t pad = digitalPinToTouchChannel(pin); + if (pad < 0) { + log_e(" No touch pad on selected pin!"); + return; + } + + if (userFunc == NULL) { + // detach ISR User Call + __touchInterruptHandlers[pad].fn = NULL; + __touchInterruptHandlers[pad].callWithArgs = false; + __touchInterruptHandlers[pad].arg = NULL; + } else { + // attach ISR User Call + __touchInit(); + __touchChannelInit(pad); + __touchInterruptHandlers[pad].fn = userFunc; + __touchInterruptHandlers[pad].callWithArgs = callWithArgs; + __touchInterruptHandlers[pad].arg = Args; + } + + if (threshold != 0) { + if (!touchStop() || !touchDisable()) { + log_e("Touch sensor stop and disable failed!"); + return; + } + + touch_channel_config_t chan_cfg = {}; + for (int i = 0; i < _sample_num; i++) { + chan_cfg.active_thresh[i] = threshold; + } + + if (touch_sensor_reconfig_channel(touch_channel_handle[pad], &chan_cfg) != ESP_OK) { + log_e("Touch sensor threshold reconfig channel failed!"); + } + + if (!touchEnable() || !touchStart()) { + log_e("Touch sensor enable and start failed!"); + } + } +} + +// it keeps backwards compatibility +static void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold) { + __touchConfigInterrupt(pin, userFunc, NULL, threshold, false); +} + +// new additional version of the API with User Args +static void __touchAttachArgsInterrupt(uint8_t pin, void (*userFunc)(void), void *args, touch_value_t threshold) { + __touchConfigInterrupt(pin, userFunc, args, threshold, true); +} + +// new additional API to detach touch ISR +static void __touchDettachInterrupt(uint8_t pin) { + __touchConfigInterrupt(pin, NULL, NULL, 0, false); // userFunc as NULL acts as detaching +} + +// /* +// External Public Touch API Functions +// */ + +bool touchInterruptGetLastStatus(uint8_t pin) { + int8_t pad = digitalPinToTouchChannel(pin); + if (pad < 0) { + return false; + } + + return __touchInterruptHandlers[pad].lastStatusIsPressed; +} + +void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold) { + int8_t pad = digitalPinToTouchChannel(pin); + if (pad < 0) { + log_e(" No touch pad on selected pin!"); + return; + } + + if (perimanGetPinBus(pin, ESP32_BUS_TYPE_TOUCH) == NULL) { + perimanSetBusDeinit(ESP32_BUS_TYPE_TOUCH, touchDetachBus); + __touchInit(); + __touchChannelInit(pad); + if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_TOUCH, (void *)(pin + 1), -1, pad)) { + log_e("Failed to set bus to Peripheral manager"); + touchDetachBus((void *)(pin + 1)); + return; + } + } + + log_v("Touch sensor deep sleep wake-up configuration for pad %d with threshold %d", pad, threshold); + if (!touchStop() || !touchDisable()) { + log_e("Touch sensor stop and disable failed!"); + return; + } + + touch_sleep_config_t deep_slp_cfg = { + .slp_wakeup_lvl = TOUCH_DEEP_SLEEP_WAKEUP, + .deep_slp_chan = touch_channel_handle[pad], + .deep_slp_thresh = {threshold}, + .deep_slp_sens_cfg = NULL, // Use the original touch sensor configuration + }; + + // Register the deep sleep wake-up + if (touch_sensor_config_sleep_wakeup(touch_sensor_handle, &deep_slp_cfg) != ESP_OK) { + log_e("Touch sensor deep sleep wake-up failed!"); + return; + } + + if (!touchEnable() || !touchStart()) { + log_e("Touch sensor enable and start failed!"); + } +} + +void touchSetDefaultThreshold(float percentage) { + s_thresh2bm_ratio = (float)percentage / 100.0f; +} + +void touchSetTiming(float measure, uint32_t sleep) { + if (initialized) { + log_e("Touch sensor already initialized. Cannot set cycles."); + return; + } + __touchSleepTime = sleep; + __touchMeasureTime = measure; +} + +void touchSetConfig(uint32_t div_num, uint8_t coarse_freq_tune, uint8_t fine_freq_tune) { + if (initialized) { + log_e("Touch sensor already initialized. Cannot set configuration."); + return; + } + _div_num = div_num; + _coarse_freq_tune = coarse_freq_tune; + _fine_freq_tune = fine_freq_tune; +} + +extern touch_value_t touchRead(uint8_t) __attribute__((weak, alias("__touchRead"))); +extern void touchAttachInterrupt(uint8_t, voidFuncPtr, touch_value_t) __attribute__((weak, alias("__touchAttachInterrupt"))); +extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value_t) __attribute__((weak, alias("__touchAttachArgsInterrupt"))); +extern void touchDetachInterrupt(uint8_t) __attribute__((weak, alias("__touchDettachInterrupt"))); + +#endif /* SOC_TOUCH_SENSOR_VERSION == 3 */ +#endif /* SOC_TOUCH_SENSOR_SUPPORTED */ diff --git a/cores/esp32/esp32-hal-touch-ng.h b/cores/esp32/esp32-hal-touch-ng.h new file mode 100644 index 00000000000..0d4eb79ac58 --- /dev/null +++ b/cores/esp32/esp32-hal-touch-ng.h @@ -0,0 +1,91 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MAIN_ESP32_HAL_TOUCH_NEW_H_ +#define MAIN_ESP32_HAL_TOUCH_NEW_H_ + +#include "soc/soc_caps.h" +#if SOC_TOUCH_SENSOR_SUPPORTED +#if SOC_TOUCH_SENSOR_VERSION == 3 // ESP32P4 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp32-hal.h" + +typedef uint32_t touch_value_t; + +/* + * Set time in us that measurement operation takes + * The result from touchRead, threshold and detection + * accuracy depend on these values. + * Note: must be called before setting up touch pads + **/ +void touchSetTiming(float measure, uint32_t sleep); + +/* + * Tune the touch pad frequency. + * Note: Must be called before setting up touch pads +*/ +void touchSetConfig(uint32_t _div_num, uint8_t coarse_freq_tune, uint8_t fine_freq_tune); + +/* + * Read touch pad value. + * You can use this method to chose a good threshold value + * to use as value for touchAttachInterrupt. + * */ +touch_value_t touchRead(uint8_t pin); + +/* + * Set function to be called if touch pad value rises by given increment (threshold). + * Use touchRead to determine a proper threshold between touched and untouched state. + * */ +void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold); +void touchAttachInterruptArg(uint8_t pin, void (*userFunc)(void *), void *arg, touch_value_t threshold); +void touchDetachInterrupt(uint8_t pin); + +/* + * Returns true when the latest ISR status for the Touchpad is that it is touched (Active) + * and false when the Touchpad is untoouched (Inactive). + * This function can be used in conjunction with ISR User callback in order to take action + * as soon as the touchpad is touched and/or released. + **/ +bool touchInterruptGetLastStatus(uint8_t pin); + +/* + * Set the default threshold for touch pads. + * The threshold is a percentage of the benchmark value. + * The default value is 1.5%. + **/ +void touchSetDefaultThreshold(float percentage); + +/* + * Setup touch pad wake up from deep sleep /light sleep with given threshold. + * When light sleep is used, all used touch pads will be able to wake up the chip. + **/ +void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_TOUCH_SENSOR_VERSION == 3 */ +#endif /* SOC_TOUCH_SENSOR_SUPPORTED */ +#endif /* MAIN_ESP32_HAL_TOUCH_H_ */ diff --git a/cores/esp32/esp32-hal-touch.c b/cores/esp32/esp32-hal-touch.c index 93e0cb1c4ac..701bf6d16c9 100644 --- a/cores/esp32/esp32-hal-touch.c +++ b/cores/esp32/esp32-hal-touch.c @@ -14,10 +14,8 @@ #include "soc/soc_caps.h" #if SOC_TOUCH_SENSOR_SUPPORTED -#if SOC_TOUCH_SENSOR_VERSION == 3 // ESP32P4 -// ToDo: Implement touch sensor for ESP32P4 -#warning "Touch sensor not implemented for ESP32P4 yet" -#else +#if SOC_TOUCH_SENSOR_VERSION <= 2 // ESP32, ESP32S2, ESP32S3 + #include "driver/touch_sensor.h" #include "esp32-hal-touch.h" #include "esp32-hal-periman.h" @@ -26,10 +24,10 @@ Internal Private Touch Data Structure and Functions */ -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 static uint16_t __touchSleepCycles = 0x1000; static uint16_t __touchMeasureCycles = 0x1000; -#elif SOC_TOUCH_SENSOR_VERSION >= 2 // ESP32S2, ESP32S3, ESP32P4 +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT; static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT; #endif @@ -55,7 +53,7 @@ static bool initialized = false; static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = {false}; static void ARDUINO_ISR_ATTR __touchISR(void *arg) { -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 uint32_t pad_intr = touch_pad_get_status(); //clear interrupt touch_pad_clear_status(); @@ -97,7 +95,7 @@ static void ARDUINO_ISR_ATTR __touchISR(void *arg) { static void __touchSetCycles(uint16_t measure, uint16_t sleep) { __touchSleepCycles = sleep; __touchMeasureCycles = measure; -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 touch_pad_set_measurement_clock_cycles(measure); #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 touch_pad_set_charge_discharge_times(measure); @@ -127,7 +125,7 @@ static void __touchInit() { esp_err_t err = ESP_OK; -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 err = touch_pad_init(); if (err != ESP_OK) { goto err; @@ -147,7 +145,7 @@ static void __touchInit() { if (err != ESP_OK) { goto err; } - touch_pad_intr_enable(); // returns ESP_OK + touch_pad_intr_enable(); // returns ESP_OK #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 err = touch_pad_init(); if (err != ESP_OK) { @@ -169,7 +167,6 @@ static void __touchInit() { touch_pad_fsm_start(); // returns ESP_OK //ISR setup moved to __touchChannelInit #endif - initialized = true; return; err: @@ -183,11 +180,11 @@ static void __touchChannelInit(int pad) { return; } -#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 +#if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 // Initial no Threshold and setup __touchInterruptHandlers[pad].fn = NULL; touch_pad_config(pad, TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK -#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 +#elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3 // Initial no Threshold and setup __touchInterruptHandlers[pad].fn = NULL; touch_pad_config(pad); // returns ESP_OK @@ -274,7 +271,7 @@ static void __touchDettachInterrupt(uint8_t pin) { External Public Touch API Functions */ -#if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC +#if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC void touchInterruptSetThresholdDirection(bool mustbeLower) { if (mustbeLower) { touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW); @@ -328,5 +325,5 @@ extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value extern void touchDetachInterrupt(uint8_t) __attribute__((weak, alias("__touchDettachInterrupt"))); extern void touchSetCycles(uint16_t, uint16_t) __attribute__((weak, alias("__touchSetCycles"))); -#endif /* SOC_TOUCH_SENSOR_VERSION == 3 */ +#endif /* SOC_TOUCH_SENSOR_VERSION <= 2 */ #endif /* SOC_TOUCH_SENSOR_SUPPORTED */ diff --git a/cores/esp32/esp32-hal-touch.h b/cores/esp32/esp32-hal-touch.h index cc140d81bb0..4b06c7db766 100644 --- a/cores/esp32/esp32-hal-touch.h +++ b/cores/esp32/esp32-hal-touch.h @@ -22,6 +22,7 @@ #include "soc/soc_caps.h" #if SOC_TOUCH_SENSOR_SUPPORTED +#if SOC_TOUCH_SENSOR_VERSION <= 2 // ESP32 ESP32S2 ESP32S3 #ifdef __cplusplus extern "C" { @@ -37,8 +38,6 @@ extern "C" { typedef uint16_t touch_value_t; #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2 ESP32S3 typedef uint32_t touch_value_t; -#elif SOC_TOUCH_SENSOR_VERSION == 3 // ESP32P4 -typedef uint32_t touch_value_t; #endif /* @@ -99,5 +98,6 @@ void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold); } #endif +#endif /* SOC_TOUCH_SENSOR_VERSION <= 2 */ #endif /* SOC_TOUCH_SENSOR_SUPPORTED */ #endif /* MAIN_ESP32_HAL_TOUCH_H_ */ diff --git a/cores/esp32/esp32-hal.h b/cores/esp32/esp32-hal.h index 60350ae960b..d80bf2f15de 100644 --- a/cores/esp32/esp32-hal.h +++ b/cores/esp32/esp32-hal.h @@ -74,6 +74,7 @@ void yield(void); #include "esp32-hal-uart.h" #include "esp32-hal-gpio.h" #include "esp32-hal-touch.h" +#include "esp32-hal-touch-ng.h" #include "esp32-hal-dac.h" #include "esp32-hal-adc.h" #include "esp32-hal-spi.h" diff --git a/cores/esp32/io_pin_remap.h b/cores/esp32/io_pin_remap.h index 73789a585e3..10f11a5bf4c 100644 --- a/cores/esp32/io_pin_remap.h +++ b/cores/esp32/io_pin_remap.h @@ -106,7 +106,7 @@ int8_t gpioNumberToDigitalPin(int8_t gpioNumber); #define spiAttachMOSI(spi, mosi) spiAttachMOSI(spi, digitalPinToGPIONumber(mosi)) #define spiAttachSS(spi, cs_num, ss) spiAttachSS(spi, cs_num, digitalPinToGPIONumber(ss)) -// cores/esp32/esp32-hal-touch.h +// cores/esp32/esp32-hal-touch.h && cores/esp32/esp32-hal-touch-ng.h #define touchInterruptGetLastStatus(pin) touchInterruptGetLastStatus(digitalPinToGPIONumber(pin)) #define touchRead(pin) touchRead(digitalPinToGPIONumber(pin)) #define touchAttachInterruptArg(pin, userFunc, arg, threshold) touchAttachInterruptArg(digitalPinToGPIONumber(pin), userFunc, arg, threshold) diff --git a/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino b/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino index 5aacf1baaf0..9d2b248ba44 100644 --- a/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino +++ b/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino @@ -15,9 +15,11 @@ Pranav Cherukupalli */ #if CONFIG_IDF_TARGET_ESP32 -#define THRESHOLD 40 /* Greater the value, more the sensitivity */ -#else //ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted) */ +#define THRESHOLD 40 /* Greater the value, more the sensitivity */ +#elif (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) #define THRESHOLD 5000 /* Lower the value, more the sensitivity */ +#else // ESP32-P4 + default for other chips (to be adjusted) */ +#define THRESHOLD 500 /* Lower the value, more the sensitivity */ #endif RTC_DATA_ATTR int bootCount = 0; @@ -88,7 +90,7 @@ void setup() { touchSleepWakeUpEnable(T3, THRESHOLD); touchSleepWakeUpEnable(T7, THRESHOLD); -#else //ESP32-S2 + ESP32-S3 +#else //ESP32-S2 + ESP32-S3 + ESP32-P4 //Setup sleep wakeup on Touch Pad 3 (GPIO3) touchSleepWakeUpEnable(T3, THRESHOLD); diff --git a/libraries/ESP32/examples/DeepSleep/TouchWakeUp/ci.json b/libraries/ESP32/examples/DeepSleep/TouchWakeUp/ci.json index cd679adefad..25c42144223 100644 --- a/libraries/ESP32/examples/DeepSleep/TouchWakeUp/ci.json +++ b/libraries/ESP32/examples/DeepSleep/TouchWakeUp/ci.json @@ -2,7 +2,6 @@ "targets": { "esp32c3": false, "esp32c6": false, - "esp32h2": false, - "esp32p4": false + "esp32h2": false } } diff --git a/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino b/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino index 0f0880902fb..3b4e5f0b9e9 100644 --- a/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino +++ b/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino @@ -3,7 +3,12 @@ This is an example how to use Touch Intrrerupts The bigger the threshold, the more sensible is the touch */ +#if CONFIG_IDF_TARGET_ESP32P4 +int threshold = 0; // when 0 is used, the benchmarked value will be used +#else int threshold = 40; +#endif + bool touch1detected = false; bool touch2detected = false; diff --git a/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json b/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json index 4363987f4d6..c0ecf9fc0a5 100644 --- a/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json +++ b/libraries/ESP32/examples/Touch/TouchInterrupt/ci.json @@ -1,8 +1,5 @@ { "requires": [ "CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y" - ], - "targets": { - "esp32p4": false - } + ] } diff --git a/libraries/ESP32/examples/Touch/TouchRead/ci.json b/libraries/ESP32/examples/Touch/TouchRead/ci.json index 4363987f4d6..c0ecf9fc0a5 100644 --- a/libraries/ESP32/examples/Touch/TouchRead/ci.json +++ b/libraries/ESP32/examples/Touch/TouchRead/ci.json @@ -1,8 +1,5 @@ { "requires": [ "CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y" - ], - "targets": { - "esp32p4": false - } + ] } diff --git a/tests/validation/touch/ci.json b/tests/validation/touch/ci.json index 1abbabeae0c..855e9bd964d 100644 --- a/tests/validation/touch/ci.json +++ b/tests/validation/touch/ci.json @@ -5,8 +5,5 @@ }, "requires": [ "CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y" - ], - "targets": { - "esp32p4": false - } + ] } diff --git a/tests/validation/touch/touch.ino b/tests/validation/touch/touch.ino index 60f6e7f7966..97aac8a65e6 100644 --- a/tests/validation/touch/touch.ino +++ b/tests/validation/touch/touch.ino @@ -2,6 +2,10 @@ #include "soc/soc_caps.h" #include "driver/touch_pad.h" +#if SOC_TOUCH_SENSOR_VERSION == 3 +#include "hal/touch_sensor_ll.h" +#endif + #if CONFIG_IDF_TARGET_ESP32 #define TEST_TOUCH_CHANNEL (9) @@ -15,11 +19,7 @@ uint8_t TOUCH_GPIOS[] = {4, 2, 15, 13, 12, 14, 27, 33, 32}; #define NO_TOUCH_GPIO 25 -#define RELEASED_VALUE 75 //75+ read value to pass test -#define PRESSED_VALUE 20 //20- read value to pass test -#define INTERRUPT_THRESHOLD 40 - -#else //ESP32S2 and ESP32S3 +#elif (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) #define TEST_TOUCH_CHANNEL (12) //14 static touch_pad_t touch_list[TEST_TOUCH_CHANNEL] = { @@ -33,7 +33,25 @@ uint8_t TOUCH_GPIOS[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 /*,13,14*/}; #define NO_TOUCH_GPIO 17 -#if CONFIG_IDF_TARGET_ESP32S2 +#else //ESP32P4 + +#define TEST_TOUCH_CHANNEL (5) //14 +static touch_pad_t touch_list[TEST_TOUCH_CHANNEL] = { + TOUCH_PAD_NUM0, TOUCH_PAD_NUM1, TOUCH_PAD_NUM2, + TOUCH_PAD_NUM3, TOUCH_PAD_NUM4, /* TOUCH_PAD_NUM5, TOUCH_PAD_NUM6, + TOUCH_PAD_NUM7, TOUCH_PAD_NUM8, TOUCH_PAD_NUM9, TOUCH_PAD_NUM10, TOUCH_PAD_NUM11, TOUCH_PAD_NUM12, TOUCH_PAD_NUM13*/ +}; + +uint8_t TOUCH_GPIOS[] = {2, 3, 4, 5, 6 /*, 7, 8, 9, 10, 11, 12 ,13, 14, 15*/}; + +#define NO_TOUCH_GPIO 17 +#endif + +#if CONFIG_IDF_TARGET_ESP32 +#define RELEASED_VALUE 75 //75+ read value to pass test +#define PRESSED_VALUE 20 //20- read value to pass test +#define INTERRUPT_THRESHOLD 40 +#elif CONFIG_IDF_TARGET_ESP32S2 #define RELEASED_VALUE 10000 //10000- read value to pass test #define PRESSED_VALUE 42000 //40000+ read value to pass test #define INTERRUPT_THRESHOLD 30000 @@ -41,12 +59,13 @@ uint8_t TOUCH_GPIOS[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 /*,13,14*/}; #define RELEASED_VALUE 25000 //25000- read value to pass test #define PRESSED_VALUE 90000 //90000+ read value to pass test #define INTERRUPT_THRESHOLD 80000 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define PRESSED_VALUE_DIFFERENCE 200 //200+ read value difference against the unpressed value +#define INTERRUPT_THRESHOLD 0 // Use benchmarked threshold #else #error Test not currently supported on this chip. Please adjust and try again! #endif -#endif - bool touch1detected = false; bool touch2detected = false; @@ -59,17 +78,25 @@ void gotTouch2() { } /* - * Change the slope to get larger value from touch sensor. + * Change the slope to get larger value from touch sensor. (Capacitor for ESP32P4) */ static void test_press_fake(touch_pad_t pad_num) { +#if SOC_TOUCH_SENSOR_VERSION <= 2 touch_pad_set_cnt_mode(pad_num, TOUCH_PAD_SLOPE_1, TOUCH_PAD_TIE_OPT_DEFAULT); +#else + touch_ll_set_internal_capacitor(0x7f); +#endif } /* - * Change the slope to get smaller value from touch sensor. + * Change the slope to get smaller value from touch sensor. (Capacitor for ESP32P4) */ static void test_release_fake(touch_pad_t pad_num) { +#if SOC_TOUCH_SENSOR_VERSION <= 2 touch_pad_set_cnt_mode(pad_num, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT); +#else + touch_ll_set_internal_capacitor(0); +#endif } /* These functions are intended to be called before and after each test. */ @@ -87,6 +114,7 @@ void tearDown(void) { */ void test_touch_read(void) { +#if SOC_TOUCH_SENSOR_VERSION <= 2 //TEST RELEASE STATE for (int i = 0; i < sizeof(TOUCH_GPIOS); i++) { #ifdef CONFIG_IDF_TARGET_ESP32 @@ -109,6 +137,29 @@ void test_touch_read(void) { TEST_ASSERT_GREATER_THAN(PRESSED_VALUE, touchRead(TOUCH_GPIOS[k])); #endif } +#else //TOUCH V3 + //TEST RELEASE STATE + touch_value_t touch_unpressed[sizeof(TOUCH_GPIOS)]; + for (int i = 0; i < sizeof(TOUCH_GPIOS); i++) { + touch_unpressed[i] = touchRead(TOUCH_GPIOS[i]); + } + + // TEST PRESS STATE + for (int j = 0; j < TEST_TOUCH_CHANNEL; j++) { + test_press_fake(touch_list[j]); + } + delay(100); + + touch_value_t touch_pressed[sizeof(TOUCH_GPIOS)]; + for (int k = 0; k < sizeof(TOUCH_GPIOS); k++) { + touch_pressed[k] = touchRead(TOUCH_GPIOS[k]); + } + + // COMPARE PRESSED > UNPRESSED + for (int l = 0; l < sizeof(TOUCH_GPIOS); l++) { + TEST_ASSERT_GREATER_THAN((touch_unpressed[l] + PRESSED_VALUE_DIFFERENCE), touch_pressed[l]); + } +#endif } void test_touch_interrtupt(void) { @@ -146,4 +197,6 @@ void setup() { UNITY_END(); } -void loop() {} +void loop() { + delay(10); +} From 83d35683c3736178de595a0ad0424ea3e8f5a4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:03:44 +0200 Subject: [PATCH 078/406] feat(sdmmc): Add SDMMC support for P4 + remove BUILTIN LED (#10460) * feat(sdmmc): Add support for P4 * fix(board): Remove builtin led * Update libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino Add missing note about power pin for P4 Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * ci(pre-commit): Apply automatic fixes * feat(sdmmc): Option to set power channel * feat(sdmmc): Update pins_arduino.h * feat(sdmmc): remove sdmmc power from periman * fix(sdmmc): use corrent variable * fix(sdmmc): Remove periman * feat(sdmmc): Toggle power pin if defined * feat(sdmmc): setPowerChannel available only when supported * feat(sdmmc): Toggle sd power pin for 200ms * fix(example): Remove p4 pins as they are listed already * feat(sdmmc): Check if power channel is specified * ci(pre-commit): Apply automatic fixes * fix(ci): codespell fix --------- Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- .../SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino | 20 ++-- .../SD_MMC/examples/SDMMC_time/SDMMC_time.ino | 1 + libraries/SD_MMC/src/SD_MMC.cpp | 106 ++++++++++++++++-- libraries/SD_MMC/src/SD_MMC.h | 6 + variants/esp32p4/pins_arduino.h | 28 +++-- 5 files changed, 138 insertions(+), 23 deletions(-) diff --git a/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino b/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino index 030caae759c..e03f5ceb25e 100644 --- a/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino +++ b/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino @@ -14,6 +14,7 @@ * Connections for ║ ║ ╔═══╩═║═║═══╗ ║ ║ ║ * full-sized ║ ║ ║ ╔═╝ ║ ║ ║ ║ ║ * SD card ║ ║ ║ ║ ║ ║ ║ ║ ║ + * ESP32-P4 Func EV | 40 39 GND 43 3V3 GND 44 43 42 | SLOT 0 (IO_MUX) * ESP32-S3 DevKit | 21 47 GND 39 3V3 GND 40 41 42 | * ESP32-S3-USB-OTG | 38 37 GND 36 3V3 GND 35 34 33 | * ESP32 | 4 2 GND 14 3V3 GND 15 13 12 | @@ -42,6 +43,7 @@ #include "FS.h" #include "SD_MMC.h" +#ifdef CONFIG_IDF_TARGET_ESP32S3 // Default pins for ESP-S3 // Warning: ESP32-S3-WROOM-2 is using most of the default GPIOs (33-37) to interface with on-board OPI flash. // If the SD_MMC is initialized with default pins it will result in rebooting loop - please @@ -54,6 +56,7 @@ int d0 = 37; int d1 = 38; int d2 = 33; int d3 = 39; // GPIO 34 is not broken-out on ESP32-S3-DevKitC-1 v1.1 +#endif void listDir(fs::FS &fs, const char *dirname, uint8_t levels) { Serial.printf("Listing directory: %s\n", dirname); @@ -211,15 +214,16 @@ void testFileIO(fs::FS &fs, const char *path) { void setup() { Serial.begin(115200); /* - // If you want to change the pin assignment on ESP32-S3 uncomment this block and the appropriate + // If you want to change the pin assignment or you get an error that some pins + // are not assigned on ESP32-S3/ESP32-P4 uncomment this block and the appropriate // line depending if you want to use 1-bit or 4-bit line. - // Please note that ESP32 does not allow pin change and will always fail. + // Please note that ESP32 does not allow pin change and setPins() will always fail. //if(! SD_MMC.setPins(clk, cmd, d0)){ //if(! SD_MMC.setPins(clk, cmd, d0, d1, d2, d3)){ - Serial.println("Pin change failed!"); - return; - } - */ + // Serial.println("Pin change failed!"); + // return; + //} + */ if (!SD_MMC.begin()) { Serial.println("Card Mount Failed"); @@ -262,4 +266,6 @@ void setup() { Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024)); } -void loop() {} +void loop() { + delay(10); +} diff --git a/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino b/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino index bd9f150f3e8..d1e933e4f4b 100644 --- a/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino +++ b/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino @@ -14,6 +14,7 @@ * Connections for ║ ║ ╔═══╩═║═║═══╗ ║ ║ ║ * full-sized ║ ║ ║ ╔═╝ ║ ║ ║ ║ ║ * SD card ║ ║ ║ ║ ║ ║ ║ ║ ║ + * ESP32-P4 Func EV | 40 39 GND 43 3V3 GND 44 43 42 | SLOT 0 (IO_MUX) * ESP32-S3 DevKit | 21 47 GND 39 3V3 GND 40 41 42 | * ESP32-S3-USB-OTG | 38 37 GND 36 3V3 GND 35 34 33 | * ESP32 | 4 2 GND 14 3V3 GND 15 13 12 | diff --git a/libraries/SD_MMC/src/SD_MMC.cpp b/libraries/SD_MMC/src/SD_MMC.cpp index 80cb150baa2..4a0962ff7e4 100644 --- a/libraries/SD_MMC/src/SD_MMC.cpp +++ b/libraries/SD_MMC/src/SD_MMC.cpp @@ -32,11 +32,14 @@ #include "ff.h" #include "esp32-hal-periman.h" +#if SOC_SDMMC_IO_POWER_EXTERNAL +#include "sd_pwr_ctrl_by_on_chip_ldo.h" +#endif + using namespace fs; SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) { -#if !defined(CONFIG_IDF_TARGET_ESP32P4) -#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && defined(BOARD_HAS_SDMMC) +#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && defined(BOARD_HAS_SDMMC) && !defined(CONFIG_IDF_TARGET_ESP32P4) _pin_clk = SDMMC_CLK; _pin_cmd = SDMMC_CMD; _pin_d0 = SDMMC_D0; @@ -45,9 +48,8 @@ SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) { _pin_d2 = SDMMC_D2; _pin_d3 = SDMMC_D3; #endif // BOARD_HAS_1BIT_SDMMC -#endif // !defined(CONFIG_IDF_TARGET_ESP32P4) -#elif SOC_SDMMC_USE_IOMUX && defined(BOARD_HAS_SDMMC) && defined(CONFIG_IDF_TARGET_ESP32) +#elif defined(SOC_SDMMC_USE_IOMUX) && defined(BOARD_HAS_SDMMC) && defined(CONFIG_IDF_TARGET_ESP32) _pin_clk = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK; _pin_cmd = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD; _pin_d0 = SDMMC_SLOT1_IOMUX_PIN_NUM_D0; @@ -57,7 +59,9 @@ SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) { _pin_d3 = SDMMC_SLOT1_IOMUX_PIN_NUM_D3; #endif // BOARD_HAS_1BIT_SDMMC -#elif SOC_SDMMC_USE_IOMUX && defined(BOARD_HAS_SDMMC) && defined(CONFIG_IDF_TARGET_ESP32P4) +// ESP32-P4 can use either IOMUX or GPIO matrix +#elif defined(BOARD_HAS_SDMMC) && defined(CONFIG_IDF_TARGET_ESP32P4) +#if defined(BOARD_SDMMC_SLOT) && (BOARD_SDMMC_SLOT == 0) _pin_clk = SDMMC_SLOT0_IOMUX_PIN_NUM_CLK; _pin_cmd = SDMMC_SLOT0_IOMUX_PIN_NUM_CMD; _pin_d0 = SDMMC_SLOT0_IOMUX_PIN_NUM_D0; @@ -66,6 +70,19 @@ SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) { _pin_d2 = SDMMC_SLOT0_IOMUX_PIN_NUM_D2; _pin_d3 = SDMMC_SLOT0_IOMUX_PIN_NUM_D3; #endif // BOARD_HAS_1BIT_SDMMC +#else + _pin_clk = SDMMC_CLK; + _pin_cmd = SDMMC_CMD; + _pin_d0 = SDMMC_D0; +#ifndef BOARD_HAS_1BIT_SDMMC + _pin_d1 = SDMMC_D1; + _pin_d2 = SDMMC_D2; + _pin_d3 = SDMMC_D3; +#endif // BOARD_HAS_1BIT_SDMMC +#endif // BOARD_SDMMC_SLOT_NO +#endif +#if defined(SOC_SDMMC_IO_POWER_EXTERNAL) && defined(BOARD_SDMMC_POWER_CHANNEL) + _power_channel = BOARD_SDMMC_POWER_CHANNEL; #endif } @@ -95,7 +112,7 @@ bool SDMMCFS::setPins(int clk, int cmd, int d0, int d1, int d2, int d3) { d2 = digitalPinToGPIONumber(d2); d3 = digitalPinToGPIONumber(d3); -#ifdef SOC_SDMMC_USE_GPIO_MATRIX +#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && !defined(CONFIG_IDF_TARGET_ESP32P4) // SoC supports SDMMC pin configuration via GPIO matrix. Save the pins for later use in SDMMCFS::begin. _pin_clk = (int8_t)clk; _pin_cmd = (int8_t)cmd; @@ -116,11 +133,42 @@ bool SDMMCFS::setPins(int clk, int cmd, int d0, int d1, int d2, int d3) { return false; } return true; +#elif defined(CONFIG_IDF_TARGET_ESP32P4) +#if defined(BOARD_SDMMC_SLOT) && (BOARD_SDMMC_SLOT == 0) + // ESP32-P4 can use either IOMUX or GPIO matrix + bool pins_ok = + (clk == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_CLK) && (cmd == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_CMD) && (d0 == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_D0) + && (((d1 == -1) && (d2 == -1) && (d3 == -1)) || ((d1 == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_D1) && (d2 == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_D2) && (d3 == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_D3))); + if (!pins_ok) { + log_e("SDMMCFS: specified pins are not supported when using IOMUX (SDMMC SLOT 0)."); + return false; + } + return true; +#else + _pin_clk = (int8_t)clk; + _pin_cmd = (int8_t)cmd; + _pin_d0 = (int8_t)d0; + _pin_d1 = (int8_t)d1; + _pin_d2 = (int8_t)d2; + _pin_d3 = (int8_t)d3; + return true; +#endif #else #error SoC not supported #endif } +#ifdef SOC_SDMMC_IO_POWER_EXTERNAL +bool SDMMCFS::setPowerChannel(int power_channel) { + if (_card != nullptr) { + log_e("SD_MMC.setPowerChannel must be called before SD_MMC.begin"); + return false; + } + _power_channel = power_channel; + return true; +} +#endif + bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_failed, int sdmmc_frequency, uint8_t maxOpenFiles) { if (_card) { return true; @@ -135,7 +183,9 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_ } //mount sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); -#ifdef SOC_SDMMC_USE_GPIO_MATRIX +#if (defined(SOC_SDMMC_USE_GPIO_MATRIX) && !defined(CONFIG_IDF_TARGET_ESP32P4)) \ + || (defined(CONFIG_IDF_TARGET_ESP32P4) && ((defined(BOARD_SDMMC_SLOT) && (BOARD_SDMMC_SLOT == 1)) || !defined(BOARD_HAS_SDMMC))) + log_d("pin_cmd: %d, pin_clk: %d, pin_d0: %d, pin_d1: %d, pin_d2: %d, pin_d3: %d", _pin_cmd, _pin_clk, _pin_d0, _pin_d1, _pin_d2, _pin_d3); // SoC supports SDMMC pin configuration via GPIO matrix. // Check that the pins have been set either in the constructor or setPins function. if (_pin_cmd == -1 || _pin_clk == -1 || _pin_d0 == -1 || (!mode1bit && (_pin_d1 == -1 || _pin_d2 == -1 || _pin_d3 == -1))) { @@ -175,7 +225,18 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_ sdmmc_host_t host = SDMMC_HOST_DEFAULT(); host.flags = SDMMC_HOST_FLAG_4BIT; +#if defined(CONFIG_IDF_TARGET_ESP32P4) && defined(BOARD_SDMMC_SLOT) && (BOARD_SDMMC_SLOT == 0) + host.slot = SDMMC_HOST_SLOT_0; + // reconfigure slot_config to remove all pins in order to use IO_MUX + slot_config = { + .cd = SDMMC_SLOT_NO_CD, + .wp = SDMMC_SLOT_NO_WP, + .width = 4, + .flags = 0, + }; +#else host.slot = SDMMC_HOST_SLOT_1; +#endif host.max_freq_khz = sdmmc_frequency; #ifdef BOARD_HAS_1BIT_SDMMC mode1bit = true; @@ -186,6 +247,34 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_ } _mode1bit = mode1bit; +#ifdef SOC_SDMMC_IO_POWER_EXTERNAL + if (_power_channel == -1) { + log_i("On-chip power channel specified, use external power for SDMMC"); + } else { + sd_pwr_ctrl_ldo_config_t ldo_config = { + .ldo_chan_id = _power_channel, + }; + sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL; + + if (sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle) != ESP_OK) { + log_e("Failed to create a new on-chip LDO power control driver"); + return false; + } + host.pwr_ctrl_handle = pwr_ctrl_handle; + } +#endif + +#if defined(BOARD_SDMMC_POWER_PIN) +#ifndef BOARD_SDMMC_POWER_ON_LEVEL +#error "BOARD_SDMMC_POWER_ON_LEVEL not defined, please define it in pins_arduino.h" +#endif + pinMode(BOARD_SDMMC_POWER_PIN, OUTPUT); + digitalWrite(BOARD_SDMMC_POWER_PIN, !BOARD_SDMMC_POWER_ON_LEVEL); + delay(200); + digitalWrite(BOARD_SDMMC_POWER_PIN, BOARD_SDMMC_POWER_ON_LEVEL); + perimanSetPinBusExtraType(BOARD_SDMMC_POWER_PIN, "SDMMC_POWER"); +#endif + esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = format_if_mount_failed, .max_files = maxOpenFiles, @@ -252,6 +341,9 @@ void SDMMCFS::end() { perimanClearPinBus(_pin_d2); perimanClearPinBus(_pin_d3); } +#if defined(BOARD_SDMMC_POWER_PIN) + perimanClearPinBus(BOARD_SDMMC_POWER_PIN); +#endif } } diff --git a/libraries/SD_MMC/src/SD_MMC.h b/libraries/SD_MMC/src/SD_MMC.h index a2bc12aed64..b6fe13a0d24 100644 --- a/libraries/SD_MMC/src/SD_MMC.h +++ b/libraries/SD_MMC/src/SD_MMC.h @@ -44,6 +44,9 @@ class SDMMCFS : public FS { int8_t _pin_d1 = -1; int8_t _pin_d2 = -1; int8_t _pin_d3 = -1; +#ifdef SOC_SDMMC_IO_POWER_EXTERNAL + int8_t _power_channel = -1; +#endif uint8_t _pdrv = 0xFF; bool _mode1bit = false; @@ -51,6 +54,9 @@ class SDMMCFS : public FS { SDMMCFS(FSImplPtr impl); bool setPins(int clk, int cmd, int d0); bool setPins(int clk, int cmd, int d0, int d1, int d2, int d3); +#ifdef SOC_SDMMC_IO_POWER_EXTERNAL + bool setPowerChannel(int power_channel); +#endif bool begin( const char *mountpoint = "/sdcard", bool mode1bit = false, bool format_if_mount_failed = false, int sdmmc_frequency = BOARD_MAX_SDMMC_FREQ, uint8_t maxOpenFiles = 5 diff --git a/variants/esp32p4/pins_arduino.h b/variants/esp32p4/pins_arduino.h index 792146f5ca2..cbb1e871ae5 100644 --- a/variants/esp32p4/pins_arduino.h +++ b/variants/esp32p4/pins_arduino.h @@ -4,15 +4,6 @@ #include #include "soc/soc_caps.h" -#define PIN_NEOPIXEL 44 -// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino -static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_NEOPIXEL; -#define BUILTIN_LED LED_BUILTIN // backward compatibility -#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN -// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() -#define RGB_BUILTIN LED_BUILTIN -#define RGB_BRIGHTNESS 64 - // BOOT_MODE 35 // BOOT_MODE2 36 pullup @@ -58,6 +49,8 @@ static const uint8_t T11 = 13; static const uint8_t T12 = 14; static const uint8_t T13 = 15; +/* ESP32-P4 EV Function board specific definitions */ +//ETH #define ETH_PHY_TYPE ETH_PHY_TLK110 #define ETH_PHY_ADDR 1 #define ETH_PHY_MDC 31 @@ -72,4 +65,21 @@ static const uint8_t T13 = 15; #define ETH_RMII_CLK 50 #define ETH_CLK_MODE EMAC_CLK_EXT_IN +//SDMMC +#define BOARD_HAS_SDMMC +#define BOARD_SDMMC_SLOT 0 +#define BOARD_SDMMC_POWER_CHANNEL 4 +#define BOARD_SDMMC_POWER_PIN 45 +#define BOARD_SDMMC_POWER_ON_LEVEL LOW + +//WIFI - ESP32C6 +#define BOARD_HAS_SDIO_ESP_HOSTED +#define BOARD_SDIO_ESP_HOSTED_CLK 18 +#define BOARD_SDIO_ESP_HOSTED_CMD 19 +#define BOARD_SDIO_ESP_HOSTED_D0 14 +#define BOARD_SDIO_ESP_HOSTED_D1 15 +#define BOARD_SDIO_ESP_HOSTED_D2 16 +#define BOARD_SDIO_ESP_HOSTED_D3 17 +#define BOARD_SDIO_ESP_HOSTED_RESET 54 + #endif /* Pins_Arduino_h */ From 9e643c08a700a62415a5c3f311788e1b1edd64fe Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 21 Oct 2024 09:45:59 -0300 Subject: [PATCH 079/406] fix(testing): Checkout proper branch for Wokwi tests and small QoL improvements (#10435) * fix(tests): Add missing newlines to output * fix(tests): Improve fibonacci test * fix(tests): Remove redundant targets from json * fix(wokwi): Checkout proper base branch for wokwi tests * feat(logging): Add logging to some tests to improve debugging * fix(ci): Make CI more permissive and improve messages * fix(tests): Bump pytest-embedded version to support P4 --- .github/scripts/tests_matrix.sh | 26 +++++++++++++ .github/workflows/dangerjs.yml | 4 +- .github/workflows/tests.yml | 38 +++++++++---------- .github/workflows/tests_results.yml | 1 + .github/workflows/tests_wokwi.yml | 36 ++++++++++++++++-- tests/performance/coremark/coremark.ino | 2 +- tests/performance/fibonacci/fibonacci.ino | 2 +- tests/performance/fibonacci/test_fibonacci.py | 33 ++++++++-------- tests/performance/psramspeed/ci.json | 8 ++-- tests/performance/psramspeed/psramspeed.ino | 2 +- tests/performance/ramspeed/ramspeed.ino | 2 +- tests/performance/superpi/superpi.ino | 2 +- tests/requirements.txt | 8 ++-- tests/validation/gpio/test_gpio.py | 10 +++++ tests/validation/nvs/test_nvs.py | 9 +++++ tests/validation/periman/test_periman.py | 8 +++- tests/validation/psram/ci.json | 7 +--- tests/validation/wifi/test_wifi.py | 9 +++++ 18 files changed, 143 insertions(+), 64 deletions(-) create mode 100644 .github/scripts/tests_matrix.sh diff --git a/.github/scripts/tests_matrix.sh b/.github/scripts/tests_matrix.sh new file mode 100644 index 00000000000..ca0b6eb8684 --- /dev/null +++ b/.github/scripts/tests_matrix.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +build_types="'validation'" +hw_types="'validation'" +wokwi_types="'validation'" +qemu_types="'validation'" + +if [[ $IS_PR != 'true' ]] || [[ $PERFORMANCE_ENABLED == 'true' ]]; then + build_types+=",'performance'" + hw_types+=",'performance'" + #wokwi_types+=",'performance'" + #qemu_types+=",'performance'" +fi + +targets="'esp32','esp32s2','esp32s3','esp32c3','esp32c6','esp32h2'" + +mkdir -p info + +echo "[$wokwi_types]" > info/wokwi_types.txt +echo "[$targets]" > info/targets.txt + +echo "build-types=[$build_types]" >> $GITHUB_OUTPUT +echo "hw-types=[$hw_types]" >> $GITHUB_OUTPUT +echo "wokwi-types=[$wokwi_types]" >> $GITHUB_OUTPUT +echo "qemu-types=[$qemu_types]" >> $GITHUB_OUTPUT +echo "targets=[$targets]" >> $GITHUB_OUTPUT diff --git a/.github/workflows/dangerjs.yml b/.github/workflows/dangerjs.yml index 9f7360bc34f..75c046731f3 100644 --- a/.github/workflows/dangerjs.yml +++ b/.github/workflows/dangerjs.yml @@ -19,4 +19,6 @@ jobs: - name: DangerJS pull request linter uses: espressif/shared-github-dangerjs@v1 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + rule-max-commits: 'false' + commit-messages-min-summary-length: '10' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 26de19d8f10..ab8baa6d14c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -57,29 +57,25 @@ jobs: hw-types: ${{ steps.set-matrix.outputs.hw-types }} wokwi-types: ${{ steps.set-matrix.outputs.wokwi-types }} qemu-types: ${{ steps.set-matrix.outputs.qemu-types }} + targets: ${{ steps.set-matrix.outputs.targets }} + env: + IS_PR: ${{ github.event.pull_request.number != null }} + PERFORMANCE_ENABLED: ${{ contains(github.event.pull_request.labels.*.name, 'perf_test') }} steps: + - name: Checkout + uses: actions/checkout@v4 + with: + sparse-checkout: .github/scripts/tests_matrix.sh + - name: Set matrix id: set-matrix - run: | - build_types='["validation"' - hw_types='["validation"' - wokwi_types='["validation"' - qemu_types='["validation"' - - is_pr=${{ github.event.pull_request.number != null }} - is_performance_enabled=${{ contains(github.event.pull_request.labels.*.name, 'perf_test') }} - - if [[ $is_pr != 'true' ]] || [[ $is_performance_enabled == 'true' ]]; then - build_types+=',"performance"' - hw_types+=',"performance"' - #wokwi_types+=',"performance"' - #qemu_types+=',"performance"' - fi + run: bash .github/scripts/tests_matrix.sh - echo "build-types=$build_types]" >> $GITHUB_OUTPUT - echo "hw-types=$hw_types]" >> $GITHUB_OUTPUT - echo "wokwi-types=$wokwi_types]" >> $GITHUB_OUTPUT - echo "qemu-types=$qemu_types]" >> $GITHUB_OUTPUT + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: matrix_info + path: info/* call-build-tests: name: Build @@ -88,7 +84,7 @@ jobs: strategy: matrix: type: ${{ fromJson(needs.gen-matrix.outputs.build-types) }} - chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'] + chip: ${{ fromJson(needs.gen-matrix.outputs.targets) }} with: type: ${{ matrix.type }} chip: ${{ matrix.chip }} @@ -105,7 +101,7 @@ jobs: fail-fast: false matrix: type: ${{ fromJson(needs.gen-matrix.outputs.hw-types) }} - chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'] + chip: ${{ fromJson(needs.gen-matrix.outputs.targets) }} with: type: ${{ matrix.type }} chip: ${{ matrix.chip }} diff --git a/.github/workflows/tests_results.yml b/.github/workflows/tests_results.yml index a255016c413..f9c572bf546 100644 --- a/.github/workflows/tests_results.yml +++ b/.github/workflows/tests_results.yml @@ -79,6 +79,7 @@ jobs: event_name: ${{ env.original_event }} files: ./artifacts/**/*.xml action_fail: true + compare_to_earlier_commit: false - name: Fail if tests failed if: ${{ env.original_conclusion == 'failure' || env.original_conclusion == 'timed_out' || github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'timed_out' }} diff --git a/.github/workflows/tests_wokwi.yml b/.github/workflows/tests_wokwi.yml index f016cad25e0..a891ca89dfd 100644 --- a/.github/workflows/tests_wokwi.yml +++ b/.github/workflows/tests_wokwi.yml @@ -22,6 +22,9 @@ jobs: outputs: pr_num: ${{ steps.set-ref.outputs.pr_num }} ref: ${{ steps.set-ref.outputs.ref }} + base: ${{ steps.set-ref.outputs.base }} + targets: ${{ steps.set-ref.outputs.targets }} + types: ${{ steps.set-ref.outputs.types }} steps: - name: Report pending uses: actions/github-script@v7 @@ -51,10 +54,18 @@ jobs: name: event_file path: artifacts/event_file + - name: Download and extract matrix info + uses: actions/download-artifact@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + name: matrix_info + path: artifacts/matrix_info + - name: Try to read PR number id: set-ref run: | - pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json) + pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json | tr -cd "[:digit:]") if [ -z "$pr_num" ] || [ "$pr_num" == "null" ]; then pr_num="" fi @@ -64,11 +75,22 @@ jobs: ref=${{ github.ref }} fi - action=$(jq -r '.action' artifacts/event_file/event.json) + action=$(jq -r '.action' artifacts/event_file/event.json | tr -cd "[:alpha:]_") if [ "$action" == "null" ]; then action="" fi + base=$(jq -r '.pull_request.base.ref' artifacts/event_file/event.json | tr -cd "[:alnum:]/_.-") + if [ -z "$base" ] || [ "$base" == "null" ]; then + base=${{ github.ref }} + fi + + types=$(cat artifacts/matrix_info/wokwi_types.txt | tr -cd "[:alpha:],[]'") + targets=$(cat artifacts/matrix_info/targets.txt | tr -cd "[:alnum:],[]'") + + echo "base = $base" + echo "targets = $targets" + echo "types = $types" echo "pr_num = $pr_num" printf "$ref" >> artifacts/ref.txt @@ -98,6 +120,9 @@ jobs: cat artifacts/conclusion.txt echo "pr_num=$pr_num" >> $GITHUB_OUTPUT + echo "base=$base" >> $GITHUB_OUTPUT + echo "targets=$targets" >> $GITHUB_OUTPUT + echo "types=$types" >> $GITHUB_OUTPUT echo "ref=$ref" >> $GITHUB_OUTPUT - name: Download and extract parent hardware results @@ -164,8 +189,8 @@ jobs: strategy: fail-fast: false matrix: - type: ['validation'] - chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'] + type: ${{ fromJson(needs.get-artifacts.outputs.types) }} + chip: ${{ fromJson(needs.get-artifacts.outputs.targets) }} steps: - name: Report pending uses: actions/github-script@v7 @@ -211,9 +236,12 @@ jobs: echo "enabled=$enabled" >> $GITHUB_OUTPUT # Note that changes to the workflows and tests will only be picked up after the PR is merged + # DO NOT CHECKOUT THE USER'S REPOSITORY IN THIS WORKFLOW. IT HAS HIGH SECURITY RISKS. - name: Checkout repository if: ${{ steps.check-tests.outputs.enabled == 'true' }} uses: actions/checkout@v4 + with: + ref: ${{ needs.get-artifacts.outputs.base || github.ref }} - uses: actions/setup-python@v5 if: ${{ steps.check-tests.outputs.enabled == 'true' }} diff --git a/tests/performance/coremark/coremark.ino b/tests/performance/coremark/coremark.ino index 776db7874db..872b53050f0 100644 --- a/tests/performance/coremark/coremark.ino +++ b/tests/performance/coremark/coremark.ino @@ -40,7 +40,7 @@ void setup() { Serial.printf("Cores: %d\n", CONFIG_SOC_CPU_CORES_NUM); Serial.flush(); for (int i = 0; i < N_RUNS; i++) { - Serial.printf("Run %d", i); + Serial.printf("Run %d\n", i); coremark_main(); Serial.flush(); } diff --git a/tests/performance/fibonacci/fibonacci.ino b/tests/performance/fibonacci/fibonacci.ino index 01fd6f7bee2..c82fd6b70d8 100644 --- a/tests/performance/fibonacci/fibonacci.ino +++ b/tests/performance/fibonacci/fibonacci.ino @@ -31,7 +31,7 @@ void setup() { Serial.printf("N: %d\n", FIB_N); Serial.flush(); for (int i = 0; i < N_RUNS; i++) { - Serial.printf("Run %d", i); + Serial.printf("Run %d\n", i); unsigned long start = millis(); fibonacci = fib(FIB_N); unsigned long elapsed = millis() - start; diff --git a/tests/performance/fibonacci/test_fibonacci.py b/tests/performance/fibonacci/test_fibonacci.py index 622ea77ee4b..ced9368184e 100644 --- a/tests/performance/fibonacci/test_fibonacci.py +++ b/tests/performance/fibonacci/test_fibonacci.py @@ -2,24 +2,21 @@ import logging import os +fib_results = {} + +def fib(n): + if n < 2: + return n + elif str(n) in fib_results: + return fib_results[str(n)] + else: + fib_results[str(n)] = fib(n - 1) + fib(n - 2) + return fib_results[str(n)] + def test_fibonacci(dut, request): LOGGER = logging.getLogger(__name__) - # Fibonacci results starting from fib(35) to fib(45) - fib_results = [ - 9227465, - 14930352, - 24157817, - 39088169, - 63245986, - 102334155, - 165580141, - 267914296, - 433494437, - 701408733, - ] - # Match "Runs: %d" res = dut.expect(r"Runs: (\d+)", timeout=60) runs = int(res.group(0).decode("utf-8").split(" ")[1]) @@ -30,7 +27,11 @@ def test_fibonacci(dut, request): res = dut.expect(r"N: (\d+)", timeout=300) fib_n = int(res.group(0).decode("utf-8").split(" ")[1]) LOGGER.info("Calculating Fibonacci({})".format(fib_n)) - assert fib_n > 30 and fib_n < 50, "Invalid Fibonacci number" + assert fib_n > 0, "Invalid Fibonacci number" + + # Calculate Fibonacci results + expected_result = fib(fib_n) + LOGGER.info("Expected Fibonacci result: {}".format(expected_result)) list_time = [] @@ -48,7 +49,7 @@ def test_fibonacci(dut, request): assert fib_result > 0, "Invalid Fibonacci result" # Check if the result is correct - assert fib_result == fib_results[fib_n - 35] + assert fib_result == expected_result # Match "Time: %lu.%03lu s" res = dut.expect(r"Time: (\d+)\.(\d+) s", timeout=300) diff --git a/tests/performance/psramspeed/ci.json b/tests/performance/psramspeed/ci.json index 8d58dbf5250..341df103671 100644 --- a/tests/performance/psramspeed/ci.json +++ b/tests/performance/psramspeed/ci.json @@ -3,9 +3,7 @@ "qemu": false, "wokwi": false }, - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + "requires": [ + "CONFIG_SPIRAM=y" + ] } diff --git a/tests/performance/psramspeed/psramspeed.ino b/tests/performance/psramspeed/psramspeed.ino index 81175e6b3a5..be91733abfc 100644 --- a/tests/performance/psramspeed/psramspeed.ino +++ b/tests/performance/psramspeed/psramspeed.ino @@ -252,7 +252,7 @@ void setup() { Serial.printf("Max test size: %d\n", MAX_TEST_SIZE); Serial.flush(); for (int i = 0; i < N_RUNS; i++) { - Serial.printf("Run %d", i); + Serial.printf("Run %d\n", i); memcpy_speed_test(dest, src, MAX_TEST_SIZE, N_COPIES); Serial.flush(); memset_speed_test(dest, FILL_VALUE, MAX_TEST_SIZE, N_COPIES); diff --git a/tests/performance/ramspeed/ramspeed.ino b/tests/performance/ramspeed/ramspeed.ino index e0ab0db4c5f..776f6540679 100644 --- a/tests/performance/ramspeed/ramspeed.ino +++ b/tests/performance/ramspeed/ramspeed.ino @@ -248,7 +248,7 @@ void setup() { Serial.printf("Max test size: %d\n", MAX_TEST_SIZE); Serial.flush(); for (int i = 0; i < N_RUNS; i++) { - Serial.printf("Run %d", i); + Serial.printf("Run %d\n", i); memcpy_speed_test(dest, src, MAX_TEST_SIZE, N_COPIES); Serial.flush(); memset_speed_test(dest, FILL_VALUE, MAX_TEST_SIZE, N_COPIES); diff --git a/tests/performance/superpi/superpi.ino b/tests/performance/superpi/superpi.ino index ffa6c932b35..7ac4b2f13d7 100644 --- a/tests/performance/superpi/superpi.ino +++ b/tests/performance/superpi/superpi.ino @@ -25,7 +25,7 @@ void setup() { Serial.printf("Digits: %d\n", DIGITS); Serial.flush(); for (int i = 0; i < N_RUNS; i++) { - Serial.printf("Run %d", i); + Serial.printf("Run %d\n", i); unsigned long start = millis(); pi_calc(DIGITS); unsigned long elapsed = millis() - start; diff --git a/tests/requirements.txt b/tests/requirements.txt index 1b43a6104f2..63d204a96b0 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,7 +1,7 @@ cryptography==43.0.1 --only-binary cryptography pytest-cov==5.0.0 -pytest-embedded-serial-esp==1.11.5 -pytest-embedded-arduino==1.11.5 -pytest-embedded-wokwi==1.11.5 -pytest-embedded-qemu==1.11.5 +pytest-embedded-serial-esp==1.11.6 +pytest-embedded-arduino==1.11.6 +pytest-embedded-wokwi==1.11.6 +pytest-embedded-qemu==1.11.6 diff --git a/tests/validation/gpio/test_gpio.py b/tests/validation/gpio/test_gpio.py index e36282561b5..f11b9fd99cc 100644 --- a/tests/validation/gpio/test_gpio.py +++ b/tests/validation/gpio/test_gpio.py @@ -1,5 +1,15 @@ +import logging + def test_gpio(dut): + LOGGER = logging.getLogger(__name__) + dut.expect_exact("Button test") + + LOGGER.info("Expecting button press 1") dut.expect_exact("Button pressed 1 times") + + LOGGER.info("Expecting button press 2") dut.expect_exact("Button pressed 2 times") + + LOGGER.info("Expecting button press 3") dut.expect_exact("Button pressed 3 times") diff --git a/tests/validation/nvs/test_nvs.py b/tests/validation/nvs/test_nvs.py index 364df56de1c..a2b4842fa91 100644 --- a/tests/validation/nvs/test_nvs.py +++ b/tests/validation/nvs/test_nvs.py @@ -1,4 +1,13 @@ +import logging + def test_nvs(dut): + LOGGER = logging.getLogger(__name__) + + LOGGER.info("Expecting counter value 0") dut.expect_exact("Current counter value: 0") + + LOGGER.info("Expecting counter value 1") dut.expect_exact("Current counter value: 1") + + LOGGER.info("Expecting counter value 2") dut.expect_exact("Current counter value: 2") diff --git a/tests/validation/periman/test_periman.py b/tests/validation/periman/test_periman.py index d8dc4b8eeb5..a2d25f5ba09 100644 --- a/tests/validation/periman/test_periman.py +++ b/tests/validation/periman/test_periman.py @@ -1,4 +1,7 @@ +import logging + def test_periman(dut): + LOGGER = logging.getLogger(__name__) peripherals = [ "GPIO", "SigmaDelta", @@ -29,9 +32,10 @@ def test_periman(dut): if peripheral in peripherals: if "not" in console_output: - assert False, f"Peripheral {peripheral} printed when it should not" + assert False, f"Output printed when it should not after peripheral {peripheral}" + LOGGER.info(f"Correct output after peripheral: {peripheral}") peripherals.remove(peripheral) else: assert False, f"Unknown peripheral: {peripheral}" - assert peripherals == [], f"Missing peripherals output: {peripherals}" + assert peripherals == [], f"Missing output after peripherals: {peripherals}" diff --git a/tests/validation/psram/ci.json b/tests/validation/psram/ci.json index fc34574cf37..341df103671 100644 --- a/tests/validation/psram/ci.json +++ b/tests/validation/psram/ci.json @@ -5,10 +5,5 @@ }, "requires": [ "CONFIG_SPIRAM=y" - ], - "targets": { - "esp32c3": false, - "esp32c6": false, - "esp32h2": false - } + ] } diff --git a/tests/validation/wifi/test_wifi.py b/tests/validation/wifi/test_wifi.py index 49dd22797d2..769283b06bd 100644 --- a/tests/validation/wifi/test_wifi.py +++ b/tests/validation/wifi/test_wifi.py @@ -1,6 +1,15 @@ +import logging + def test_wifi(dut): + LOGGER = logging.getLogger(__name__) + + LOGGER.info("Starting WiFi Scan") dut.expect_exact("Scan start") dut.expect_exact("Scan done") dut.expect_exact("Wokwi-GUEST") + LOGGER.info("WiFi Scan done") + + LOGGER.info("Connecting to WiFi") dut.expect_exact("WiFi connected") dut.expect_exact("IP address:") + LOGGER.info("WiFi connected") From f668557b547ddd25e464977bfbdc3d41afbdc319 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:22:02 -0300 Subject: [PATCH 080/406] Enable tests for ESP32P4 --- .github/scripts/tests_matrix.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/tests_matrix.sh b/.github/scripts/tests_matrix.sh index ca0b6eb8684..74fece91f8e 100644 --- a/.github/scripts/tests_matrix.sh +++ b/.github/scripts/tests_matrix.sh @@ -12,7 +12,7 @@ if [[ $IS_PR != 'true' ]] || [[ $PERFORMANCE_ENABLED == 'true' ]]; then #qemu_types+=",'performance'" fi -targets="'esp32','esp32s2','esp32s3','esp32c3','esp32c6','esp32h2'" +targets="'esp32','esp32s2','esp32s3','esp32c3','esp32c6','esp32h2','esp32p4'" mkdir -p info From c40444ab338e6c33c5160ee12dfe36246c482025 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 21 Oct 2024 10:42:43 -0300 Subject: [PATCH 081/406] feat(matter): initial commit with arduino matter lib (#10467) * feat(matter): initial commit with arduino matter lib * feat(matter): add matter library to cmakelists.txt * fix(matter): add correct guard for ci * fix(matter): using correct ci requirements in ci.json * fix(matter): using correct ci requirements in header files * fix(matter): using correct ci requirements header and examples * fix(typo): typo and commentaries * fix(typo): typo and commentaries * fix(typo): typo and commentaries * fix(commentary): longer explanation * feat(matter): api simplification with begin * feat(matter): testing flashmode=qio in CI * feat(matter): testing flashmode=qio in CI * fix(matter): changes CI FQBN * fix(matte): include all fqbn in ci.json using qio * fix(matter): revert ci and guard changes * fix(matter): typo and commentaties * feat(matter): adds a light toggle switch button * feat(matter): improved the button control * feat(matter): using switch instead of if() for attibute change * fix(matter): switch/case scope * fix(matter): problems found after pressing reset * feat(matter): improve example using preferences * fix(pre-commit): Fix and apply pre-commit hooks --------- Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> --- .pre-commit-config.yaml | 1 + CMakeLists.txt | 5 + .../MatterCommissionTest.ino | 65 +++++++ .../examples/MatterCommissionTest/ci.json | 7 + .../MatterComposedLights.ino | 94 ++++++++++ .../examples/MatterComposedLights/ci.json | 7 + .../MatterOnOffLight/MatterOnOffLight.ino | 138 +++++++++++++++ .../Matter/examples/MatterOnOffLight/ci.json | 7 + libraries/Matter/keywords.txt | 35 ++++ libraries/Matter/library.properties | 9 + libraries/Matter/src/Matter.cpp | 163 ++++++++++++++++++ libraries/Matter/src/Matter.h | 40 +++++ libraries/Matter/src/MatterEndPoint.h | 23 +++ libraries/Matter/src/MatterOnOffLight.cpp | 107 ++++++++++++ libraries/Matter/src/MatterOnOffLight.h | 34 ++++ 15 files changed, 735 insertions(+) create mode 100644 libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino create mode 100644 libraries/Matter/examples/MatterCommissionTest/ci.json create mode 100644 libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino create mode 100644 libraries/Matter/examples/MatterComposedLights/ci.json create mode 100644 libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino create mode 100644 libraries/Matter/examples/MatterOnOffLight/ci.json create mode 100644 libraries/Matter/keywords.txt create mode 100644 libraries/Matter/library.properties create mode 100644 libraries/Matter/src/Matter.cpp create mode 100644 libraries/Matter/src/Matter.h create mode 100644 libraries/Matter/src/MatterEndPoint.h create mode 100644 libraries/Matter/src/MatterOnOffLight.cpp create mode 100644 libraries/Matter/src/MatterOnOffLight.h diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0aff5b6f07b..6a949631bd9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,6 +26,7 @@ repos: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - id: pretty-format-json + stages: [manual] args: [--autofix] types_or: [json] exclude: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 6688a97803d..e552299b8aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ set(ARDUINO_ALL_LIBRARIES HTTPUpdate Insights LittleFS + Matter NetBIOS Network OpenThread @@ -165,6 +166,10 @@ set(ARDUINO_LIBRARY_OpenThread_SRCS libraries/OpenThread/src/OThreadCLI.cpp libraries/OpenThread/src/OThreadCLI_Util.cpp) +set(ARDUINO_LIBRARY_Matter_SRCS + libraries/Matter/src/MatterOnOffLight.cpp + libraries/Matter/src/Matter.cpp) + set(ARDUINO_LIBRARY_PPP_SRCS libraries/PPP/src/PPP.cpp libraries/PPP/src/ppp.c) diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino new file mode 100644 index 00000000000..a9afb0c4484 --- /dev/null +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -0,0 +1,65 @@ +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +#include +MatterOnOffLight OnOffLight; + +// WiFi is manually set and started + +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(100); + } + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // enable IPv6 + WiFi.enableIPv6(true); + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\r\nWiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + delay(500); + + // Initialize at least one Matter EndPoint + OnOffLight.begin(); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); +} + +void loop() { + // Check Matter Commissioning state + if (!Matter.isDeviceCommissioned()) { + Serial.println(""); + Serial.println("Matter Node is not commissioned yet."); + Serial.println("Initiate the device discovery in your Matter environment."); + Serial.println("Commission it to your Matter hub with the manual pairing code or QR code"); + Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str()); + Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str()); + // waits for Matter Light Commissioning. + while (!Matter.isDeviceCommissioned()) { + delay(5000); + Serial.println("Matter Fabric not commissioned yet. Waiting for commissioning."); + } + } + Serial.println("Matter Node is commissioned and connected to Wi-Fi."); + Serial.println("====> Decommissioning in 30 seconds. <===="); + delay(30000); + Matter.decommission(); + Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); +} diff --git a/libraries/Matter/examples/MatterCommissionTest/ci.json b/libraries/Matter/examples/MatterCommissionTest/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterCommissionTest/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] +} diff --git a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino new file mode 100644 index 00000000000..63f154d4492 --- /dev/null +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -0,0 +1,94 @@ +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// There will be 3 On/Off Light Endpoints in the same Node +#include +MatterOnOffLight OnOffLight1; +MatterOnOffLight OnOffLight2; +MatterOnOffLight OnOffLight3; + +// Matter Protocol Endpoint Callback for each Light Accessory +bool setLightOnOff1(bool state) { + Serial.printf("CB-Light1 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +bool setLightOnOff2(bool state) { + Serial.printf("CB-Light2 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +bool setLightOnOff3(bool state) { + Serial.printf("CB-Light3 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +// WiFi is manually set and started + +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(100); + } + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // enable IPv6 + WiFi.enableIPv6(true); + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\r\nWiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + delay(500); + + // Initialize all 3 Matter EndPoints + OnOffLight1.begin(); + OnOffLight2.begin(); + OnOffLight3.begin(); + OnOffLight1.onChangeOnOff(setLightOnOff1); + OnOffLight2.onChangeOnOff(setLightOnOff2); + OnOffLight3.onChangeOnOff(setLightOnOff3); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); +} + +void loop() { + // Check Matter Light Commissioning state + if (!Matter.isDeviceCommissioned()) { + Serial.println(""); + Serial.println("Matter Node is not commissioned yet."); + Serial.println("Initiate the device discovery in your Matter environment."); + Serial.println("Commission it to your Matter hub with the manual pairing code or QR code"); + Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str()); + Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str()); + // waits for Matter Light Commissioning. + uint32_t timeCount = 0; + while (!Matter.isDeviceCommissioned()) { + delay(100); + if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec + Serial.println("Matter Node not commissioned yet. Waiting for commissioning."); + } + } + Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); + } + + //displays the Light state every 3 seconds + Serial.println("======================"); + Serial.printf("Matter Light #1 is %s\r\n", OnOffLight1.getOnOff() ? "ON" : "OFF"); + Serial.printf("Matter Light #2 is %s\r\n", OnOffLight2.getOnOff() ? "ON" : "OFF"); + Serial.printf("Matter Light #3 is %s\r\n", OnOffLight3.getOnOff() ? "ON" : "OFF"); + delay(3000); +} diff --git a/libraries/Matter/examples/MatterComposedLights/ci.json b/libraries/Matter/examples/MatterComposedLights/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterComposedLights/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] +} diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino new file mode 100644 index 00000000000..64981b23a66 --- /dev/null +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -0,0 +1,138 @@ +// Matter Manager +#include +#include +#include + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +#include +MatterOnOffLight OnOffLight; + +// it will keep last OnOff state stored, using Preferences +Preferences lastStatePref; + +// set your board LED pin here +#ifdef LED_BUILTIN +const uint8_t ledPin = LED_BUILTIN; +#else +const uint8_t ledPin = 2; // Set your pin here if your board has not defined LED_BUILTIN +#warning "Do not forget to set the LED pin" +#endif + +// set your board USER BUTTON pin here +const uint8_t buttonPin = 0; // Set your pin here. Using BOOT Button. C6/C3 use GPIO9. + +// Matter Protocol Endpoint Callback +bool setLightOnOff(bool state) { + Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF"); + if (state) { + digitalWrite(ledPin, HIGH); + } else { + digitalWrite(ledPin, LOW); + } + // store last OnOff state for when the Light is restarted / power goes off + lastStatePref.putBool("lastOnOffState", state); + // This callback must return the success state to Matter core + return true; +} + +// WiFi is manually set and started + +const char *ssid = "Apartment B15"; // Change this to your WiFi SSID +const char *password = "flat-pony-body"; // Change this to your WiFi password + +void setup() { + // Initialize the USER BUTTON (Boot button) GPIO that will act as a toggle switch + pinMode(buttonPin, INPUT_PULLUP); + // Initialize the LED (light) GPIO and Matter End Point + pinMode(ledPin, OUTPUT); + + Serial.begin(115200); + while (!Serial) { + delay(100); + } + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // enable IPv6 + WiFi.enableIPv6(true); + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\r\nWiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + delay(500); + + // Initialize Matter EndPoint + lastStatePref.begin("matterLight", false); + bool lastOnOffState = lastStatePref.getBool("lastOnOffState", true); + OnOffLight.begin(lastOnOffState); + OnOffLight.onChangeOnOff(setLightOnOff); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + // This may be a restart of a already commissioned Matter accessory + if (Matter.isDeviceCommissioned()) { + Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); + Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); + setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state + } +} +// Button control +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t debouceTime = 250; // button debouncing time (ms) +const uint32_t decommissioningTimeout = 10000; // keep the button pressed for 10s to decommission the light + +void loop() { + // Check Matter Light Commissioning state, which may change during execution of loop() + if (!Matter.isDeviceCommissioned()) { + Serial.println(""); + Serial.println("Matter Node is not commissioned yet."); + Serial.println("Initiate the device discovery in your Matter environment."); + Serial.println("Commission it to your Matter hub with the manual pairing code or QR code"); + Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str()); + Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str()); + // waits for Matter Light Commissioning. + uint32_t timeCount = 0; + while (!Matter.isDeviceCommissioned()) { + delay(100); + if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec + Serial.println("Matter Node not commissioned yet. Waiting for commissioning."); + } + } + Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); + setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state + Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); + } + + // A button is also used to control the light + // Check if the button has been pressed + if (digitalRead(buttonPin) == LOW && !button_state) { + // deals with button debouncing + button_time_stamp = millis(); // record the time while the button is pressed. + button_state = true; // pressed. + } + + // Onboard User Button is used as a Light toggle switch or to decommission it + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) { + button_state = false; // released + // Toggle button is released - toggle the light + Serial.println("User button released. Toggling Light!"); + OnOffLight.toggle(); // Matter Controller also can see the change + + // Factory reset is triggered if the button is pressed longer than 10 seconds + if (time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + OnOffLight.setOnOff(false); // turn the light off + Matter.decommission(); + } + } +} diff --git a/libraries/Matter/examples/MatterOnOffLight/ci.json b/libraries/Matter/examples/MatterOnOffLight/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterOnOffLight/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] +} diff --git a/libraries/Matter/keywords.txt b/libraries/Matter/keywords.txt new file mode 100644 index 00000000000..7ff3e90f3b4 --- /dev/null +++ b/libraries/Matter/keywords.txt @@ -0,0 +1,35 @@ +####################################### +# Syntax Coloring Map For OpenThread +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Matter KEYWORD1 +MatterOnOffLight KEYWORD1 +MatterEndPoint KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +start KEYWORD2 +getManualPairingCode KEYWORD2 +getOnboardingQRCodeUrl KEYWORD2 +isDeviceCommissioned KEYWORD2 +isWiFiConnected KEYWORD2 +isThreadConnected KEYWORD2 +isDeviceConnected KEYWORD2 +decommission KEYWORD2 +attributeChangeCB KEYWORD2 +setOnOff KEYWORD2 +getOnOff KEYWORD2 +toggle KEYWORD2 +onChangeOnOff KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/Matter/library.properties b/libraries/Matter/library.properties new file mode 100644 index 00000000000..e08c750fb59 --- /dev/null +++ b/libraries/Matter/library.properties @@ -0,0 +1,9 @@ +name=Matter +version=3.1.0 +author=Rodrigo Garcia | GitHub @SuGlider +maintainer=Rodrigo Garcia +sentence=Library for supporting Matter environment on ESP32. +paragraph=This library implements Matter accessories using WiFi network. +category=Communication +url=https://github.com/espressif/arduino-esp32/ +architectures=esp32 diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp new file mode 100644 index 00000000000..49504babac0 --- /dev/null +++ b/libraries/Matter/src/Matter.cpp @@ -0,0 +1,163 @@ +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include "MatterEndPoint.h" + +using namespace esp_matter; +using namespace esp_matter::attribute; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +constexpr auto k_timeout_seconds = 300; + +static bool _matter_has_started = false; +static node::config_t node_config; +static node_t *deviceNode = NULL; + +typedef void *app_driver_handle_t; +esp_err_t matter_light_attribute_update( + app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val +); + +// This callback is called for every attribute update. The callback implementation shall +// handle the desired attributes and return an appropriate error code. If the attribute +// is not of your interest, please do not return an error code and strictly return ESP_OK. +static esp_err_t app_attribute_update_cb( + attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data +) { + esp_err_t err = ESP_OK; + MatterEndPoint *ep = (MatterEndPoint *)priv_data; // endpoint pointer to base class + switch (type) { + case PRE_UPDATE: // Callback before updating the value in the database + log_i("Attribute update callback: PRE_UPDATE"); + if (ep != NULL) { + err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; + } + break; + case POST_UPDATE: // Callback after updating the value in the database + log_i("Attribute update callback: POST_UPDATE"); + break; + case READ: // Callback for reading the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. + log_i("Attribute update callback: READ"); + break; + case WRITE: // Callback for writing the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. + log_i("Attribute update callback: WRITE"); + break; + default: log_i("Attribute update callback: Unknown type %d", type); + } + return err; +} + +// This callback is invoked when clients interact with the Identify Cluster. +// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light). +static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id, uint8_t effect_variant, void *priv_data) { + log_i("Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant); + return ESP_OK; +} + +// This callback is invoked for all Matter events. The application can handle the events as required. +static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { + switch (event->Type) { + case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged: + log_i( + "Interface %s Address changed", event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned ? "IPv4" : "IPV6" + ); + break; + case chip::DeviceLayer::DeviceEventType::kCommissioningComplete: log_i("Commissioning complete"); break; + case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired: log_i("Commissioning failed, fail safe timer expired"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted: log_i("Commissioning session started"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped: log_i("Commissioning session stopped"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: log_i("Commissioning window opened"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: log_i("Commissioning window closed"); break; + case chip::DeviceLayer::DeviceEventType::kFabricRemoved: + { + log_i("Fabric removed successfully"); + if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0) { + log_i("No fabric left, opening commissioning window"); + chip::CommissioningWindowManager &commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager(); + constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(k_timeout_seconds); + if (!commissionMgr.IsCommissioningWindowOpen()) { + // After removing last fabric, it does not remove the Wi-Fi credentials and still has IP connectivity so, only advertising on DNS-SD. + CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(kTimeoutSeconds, chip::CommissioningWindowAdvertisement::kDnssdOnly); + if (err != CHIP_NO_ERROR) { + log_e("Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format()); + } + } + } + break; + } + case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved: log_i("Fabric will be removed"); break; + case chip::DeviceLayer::DeviceEventType::kFabricUpdated: log_i("Fabric is updated"); break; + case chip::DeviceLayer::DeviceEventType::kFabricCommitted: log_i("Fabric is committed"); break; + case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized: log_i("BLE deinitialized and memory reclaimed"); break; + default: break; + } +} + +void ArduinoMatter::_init() { + if (_matter_has_started) { + return; + } + + // Create a Matter node and add the mandatory Root Node device type on endpoint 0 + // node handle can be used to add/modify other endpoints. + deviceNode = node::create(&node_config, app_attribute_update_cb, app_identification_cb); + if (deviceNode == nullptr) { + log_e("Failed to create Matter node"); + return; + } + + _matter_has_started = true; +} + +void ArduinoMatter::begin() { + if (!_matter_has_started) { + log_w("No Matter endpoint has been created. Please create an endpoint first."); + return; + } + + /* Matter start */ + esp_err_t err = esp_matter::start(app_event_cb); + if (err != ESP_OK) { + log_e("Failed to start Matter, err:%d", err); + _matter_has_started = false; + } +} + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +bool ArduinoMatter::isThreadConnected() { + return false; // Thread Network TBD +} +#endif + +bool ArduinoMatter::isDeviceCommissioned() { + return chip::Server::GetInstance().GetFabricTable().FabricCount() > 0; +} + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION +bool ArduinoMatter::isWiFiConnected() { + return chip::DeviceLayer::ConnectivityMgr().IsWiFiStationConnected(); +} +#endif + +bool ArduinoMatter::isDeviceConnected() { + bool retCode = false; +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + retCode |= ArduinoMatter::isThreadConnected(); +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + retCode |= ArduinoMatter::isWiFiConnected(); +#endif + return retCode; +} + +void ArduinoMatter::decommission() { + esp_matter::factory_reset(); +} + +// Global Matter Object +ArduinoMatter Matter; + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h new file mode 100644 index 00000000000..a1ce0f2f644 --- /dev/null +++ b/libraries/Matter/src/Matter.h @@ -0,0 +1,40 @@ +#pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +using namespace esp_matter; + +class ArduinoMatter { +public: + static inline String getManualPairingCode() { + // return the pairing code for manual pairing + return String("34970112332"); + } + static inline String getOnboardingQRCodeUrl() { + // return the URL for the QR code for onboarding + return String("https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00"); + } + static void begin(); + static bool isDeviceCommissioned(); +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + static bool isWiFiConnected(); +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + static bool isThreadConnected(); +#endif + static bool isDeviceConnected(); + static void decommission(); + + // list of Matter EndPoints Friend Classes + friend class MatterOnOffLight; + +protected: + static void _init(); +}; + +extern ArduinoMatter Matter; + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndPoint.h b/libraries/Matter/src/MatterEndPoint.h new file mode 100644 index 00000000000..2be5bf5bb5d --- /dev/null +++ b/libraries/Matter/src/MatterEndPoint.h @@ -0,0 +1,23 @@ +#pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +// Matter Endpoint Base Class. Controls the endpoint ID and allows the child class to overwrite attribute change call +class MatterEndPoint { +public: + uint16_t getEndPointId() { + return endpoint_id; + } + void setEndPointId(uint16_t ep) { + endpoint_id = ep; + } + + virtual bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) = 0; + +protected: + uint16_t endpoint_id = 0; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterOnOffLight.cpp b/libraries/Matter/src/MatterOnOffLight.cpp new file mode 100644 index 00000000000..7e8926ffdef --- /dev/null +++ b/libraries/Matter/src/MatterOnOffLight.cpp @@ -0,0 +1,107 @@ +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +bool MatterOnOffLight::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) { + bool ret = true; + if (!started) { + log_w("Matter On-Off Light device has not begun."); + return false; + } + + if (endpoint_id == getEndPointId()) { + if (cluster_id == OnOff::Id) { + if (attribute_id == OnOff::Attributes::OnOff::Id) { + if (_onChangeCB != NULL) { + ret = _onChangeCB(val->val.b); + log_d("OnOffLight state changed to %d", val->val.b); + if (ret == true) { + state = val->val.b; + } + } + } + } + } + return ret; +} + +MatterOnOffLight::MatterOnOffLight() {} + +MatterOnOffLight::~MatterOnOffLight() { + end(); +} + +bool MatterOnOffLight::begin(bool initialState) { + ArduinoMatter::_init(); + on_off_light::config_t light_config; + light_config.on_off.on_off = initialState; + state = initialState; + light_config.on_off.lighting.start_up_on_off = nullptr; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = on_off_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create on-off light endpoint"); + return false; + } + + setEndPointId(endpoint::get_id(endpoint)); + log_i("On-Off Light created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterOnOffLight::end() { + started = false; +} + +bool MatterOnOffLight::setOnOff(bool newState) { + if (!started) { + log_w("Matter On-Off Light device has not begun."); + return false; + } + + // avoid processing the a "no-change" + if (state == newState) { + return true; + } + + state = newState; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, OnOff::Id); + attribute_t *attribute = attribute::get(cluster, OnOff::Attributes::OnOff::Id); + + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + + if (val.val.b != state) { + val.val.b = state; + attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); + } + return true; +} + +bool MatterOnOffLight::getOnOff() { + return state; +} + +bool MatterOnOffLight::toggle() { + return setOnOff(!state); +} + +MatterOnOffLight::operator bool() { + return getOnOff(); +} + +void MatterOnOffLight::operator=(bool newState) { + setOnOff(newState); +} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterOnOffLight.h b/libraries/Matter/src/MatterOnOffLight.h new file mode 100644 index 00000000000..39220652e21 --- /dev/null +++ b/libraries/Matter/src/MatterOnOffLight.h @@ -0,0 +1,34 @@ +#pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterOnOffLight : public MatterEndPoint { +public: + MatterOnOffLight(); + ~MatterOnOffLight(); + virtual bool begin(bool initialState = false); // default initial state is off + void end(); // this will just stop processing Light Matter events + + bool setOnOff(bool newState); // returns true if successful + bool getOnOff(); // returns current light state + bool toggle(); // returns true if successful + + operator bool(); // returns current light state + void operator=(bool state); // turns light on or off + // this function is called by Matter internal event processor. It could be overwritten by the application, if necessary. + bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val); + // User Callback for whenever the Light state is changed by the Matter Controller + using EndPointCB = std::function; + void onChangeOnOff(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + +protected: + bool started = false; + bool state = false; // default initial state is off, but it can be changed by begin(bool) + EndPointCB _onChangeCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ From 01789a7a894bee8c75e25a6c99b5059174c9b8a5 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:29:05 -0300 Subject: [PATCH 082/406] fix(formatting): Fix formatting and disable JSON hook (#10492) --- .pre-commit-config.yaml | 1 + tests/performance/fibonacci/test_fibonacci.py | 1 + tests/validation/gpio/test_gpio.py | 1 + tests/validation/nvs/test_nvs.py | 1 + tests/validation/periman/test_periman.py | 1 + tests/validation/wifi/test_wifi.py | 1 + 6 files changed, 6 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0aff5b6f07b..6a949631bd9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,6 +26,7 @@ repos: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - id: pretty-format-json + stages: [manual] args: [--autofix] types_or: [json] exclude: | diff --git a/tests/performance/fibonacci/test_fibonacci.py b/tests/performance/fibonacci/test_fibonacci.py index ced9368184e..cf560d9691c 100644 --- a/tests/performance/fibonacci/test_fibonacci.py +++ b/tests/performance/fibonacci/test_fibonacci.py @@ -4,6 +4,7 @@ fib_results = {} + def fib(n): if n < 2: return n diff --git a/tests/validation/gpio/test_gpio.py b/tests/validation/gpio/test_gpio.py index f11b9fd99cc..8aa3a42dcc6 100644 --- a/tests/validation/gpio/test_gpio.py +++ b/tests/validation/gpio/test_gpio.py @@ -1,5 +1,6 @@ import logging + def test_gpio(dut): LOGGER = logging.getLogger(__name__) diff --git a/tests/validation/nvs/test_nvs.py b/tests/validation/nvs/test_nvs.py index a2b4842fa91..424095a49ba 100644 --- a/tests/validation/nvs/test_nvs.py +++ b/tests/validation/nvs/test_nvs.py @@ -1,5 +1,6 @@ import logging + def test_nvs(dut): LOGGER = logging.getLogger(__name__) diff --git a/tests/validation/periman/test_periman.py b/tests/validation/periman/test_periman.py index a2d25f5ba09..2728abcef80 100644 --- a/tests/validation/periman/test_periman.py +++ b/tests/validation/periman/test_periman.py @@ -1,5 +1,6 @@ import logging + def test_periman(dut): LOGGER = logging.getLogger(__name__) peripherals = [ diff --git a/tests/validation/wifi/test_wifi.py b/tests/validation/wifi/test_wifi.py index 769283b06bd..5049aae7b85 100644 --- a/tests/validation/wifi/test_wifi.py +++ b/tests/validation/wifi/test_wifi.py @@ -1,5 +1,6 @@ import logging + def test_wifi(dut): LOGGER = logging.getLogger(__name__) From f1f0e4d4f302f10c663beac581bda7bdb8039270 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 21 Oct 2024 14:43:54 -0300 Subject: [PATCH 083/406] Update MatterOnOffLight.ino --- .../Matter/examples/MatterOnOffLight/MatterOnOffLight.ino | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index 64981b23a66..736e033e3d2 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -37,9 +37,8 @@ bool setLightOnOff(bool state) { } // WiFi is manually set and started - -const char *ssid = "Apartment B15"; // Change this to your WiFi SSID -const char *password = "flat-pony-body"; // Change this to your WiFi password +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password void setup() { // Initialize the USER BUTTON (Boot button) GPIO that will act as a toggle switch From e509d33d27a6933223679d5813245e10481ab5a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Mon, 21 Oct 2024 23:56:18 +0200 Subject: [PATCH 084/406] fix(ci): Chnage approach in listing the changed boards (#10495) --- .github/scripts/find_new_boards.sh | 54 +++++++++--------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/.github/scripts/find_new_boards.sh b/.github/scripts/find_new_boards.sh index 77c98877d2a..083f1448e83 100755 --- a/.github/scripts/find_new_boards.sh +++ b/.github/scripts/find_new_boards.sh @@ -8,53 +8,32 @@ url="https://api.github.com/repos/$owner_repository/pulls/$pr_number/files" echo $url # Get changes in boards.txt file from PR -Patch=$(curl $url | jq -r '.[] | select(.filename == "boards.txt") | .patch ') +Boards_modified_url=$(curl -s $url | jq -r '.[] | select(.filename == "boards.txt") | .raw_url') -# Extract only changed lines number and count -substring_patch=$(echo "$Patch" | grep -o '@@[^@]*@@') +# Echo the modified boards.txt file URL +echo "Modified boards.txt file URL:" +echo $Boards_modified_url -params_array=() +# Download the modified boards.txt file +curl -L -o boards_pr.txt $Boards_modified_url -IFS=$'\n' read -d '' -ra params <<< $(echo "$substring_patch" | grep -oE '[-+][0-9]+,[0-9]+') +# Compare boards.txt file in the repo with the modified file +diff=$(diff -u boards.txt boards_pr.txt) -for param in "${params[@]}" -do - echo "The parameter is $param" - params_array+=("$param") -done +# Extract added or modified lines (lines starting with '+' or '-') +modified_lines=$(echo "$diff" | grep -E '^[+-][^+-]') boards_array=() previous_board="" file="boards.txt" -# Loop through boards.txt file and extract all boards that were added -for (( c=0; c<${#params_array[@]}; c+=2 )) +# Extract board names from the modified lines, and add them to the boards_array +while read -r line do - deletion_count=$( echo "${params_array[c]}" | cut -d',' -f2 | cut -d' ' -f1 ) - addition_line=$( echo "${params_array[c+1]}" | cut -d'+' -f2 | cut -d',' -f1 ) - addition_count=$( echo "${params_array[c+1]}" | cut -d'+' -f2 | cut -d',' -f2 | cut -d' ' -f1 ) - addition_end=$(($addition_line+$addition_count)) - - addition_line=$(($addition_line + 3)) - addition_end=$(($addition_end - $deletion_count)) - - echo $addition_line - echo $addition_end - - i=0 - - while read -r line - do - i=$((i+1)) - if [ $i -lt $addition_line ] - then - continue - elif [ $i -gt $addition_end ] - then - break - fi board_name=$(echo "$line" | cut -d '.' -f1 | cut -d '#' -f1) - if [ "$board_name" != "" ] && [ "$board_name" != "esp32_family" ] + # remove + or - from the board name at the beginning + board_name=$(echo "$board_name" | sed 's/^[+-]//') + if [ "$board_name" != "" ] && [ "$board_name" != "+" ] && [ "$board_name" != "-" ] && [ "$board_name" != "esp32_family" ] then if [ "$board_name" != "$previous_board" ] then @@ -63,8 +42,7 @@ do echo "Added 'espressif:esp32:$board_name' to array" fi fi - done < "$file" -done +done <<< "$modified_lines" # Create JSON like string with all boards found and pass it to env variable board_count=${#boards_array[@]} From 0045cfa658a4cbcbb800462b9e986966c32ed198 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 21 Oct 2024 19:23:28 -0300 Subject: [PATCH 085/406] fix(matter): change place of wifi credentials in code --- .../Matter/examples/MatterOnOffLight/MatterOnOffLight.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index 736e033e3d2..751bcb3d99e 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -22,6 +22,10 @@ const uint8_t ledPin = 2; // Set your pin here if your board has not defined LE // set your board USER BUTTON pin here const uint8_t buttonPin = 0; // Set your pin here. Using BOOT Button. C6/C3 use GPIO9. +// WiFi is manually set and started +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password + // Matter Protocol Endpoint Callback bool setLightOnOff(bool state) { Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF"); @@ -36,10 +40,6 @@ bool setLightOnOff(bool state) { return true; } -// WiFi is manually set and started -const char *ssid = "your-ssid"; // Change this to your WiFi SSID -const char *password = "your-password"; // Change this to your WiFi password - void setup() { // Initialize the USER BUTTON (Boot button) GPIO that will act as a toggle switch pinMode(buttonPin, INPUT_PULLUP); From 7a33a9eeffd9ff69aaad72aead4d79d532cc1235 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 21 Oct 2024 19:25:20 -0300 Subject: [PATCH 086/406] fix(matter): change the place of wifi credentials in the code --- .../MatterComposedLights/MatterComposedLights.ino | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino index 63f154d4492..5d4acb557f5 100644 --- a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -9,6 +9,10 @@ MatterOnOffLight OnOffLight1; MatterOnOffLight OnOffLight2; MatterOnOffLight OnOffLight3; +// WiFi is manually set and started +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password + // Matter Protocol Endpoint Callback for each Light Accessory bool setLightOnOff1(bool state) { Serial.printf("CB-Light1 changed state to: %s\r\n", state ? "ON" : "OFF"); @@ -25,11 +29,6 @@ bool setLightOnOff3(bool state) { return true; } -// WiFi is manually set and started - -const char *ssid = "your-ssid"; // Change this to your WiFi SSID -const char *password = "your-password"; // Change this to your WiFi password - void setup() { Serial.begin(115200); while (!Serial) { From 8ac076c44c45a80b9f02ed197340241d6894fd41 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 21 Oct 2024 19:26:34 -0300 Subject: [PATCH 087/406] fix(matter): empty line removing - style --- .../examples/MatterCommissionTest/MatterCommissionTest.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino index a9afb0c4484..48ec0355092 100644 --- a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -8,7 +8,6 @@ MatterOnOffLight OnOffLight; // WiFi is manually set and started - const char *ssid = "your-ssid"; // Change this to your WiFi SSID const char *password = "your-password"; // Change this to your WiFi password From 20a28b58bc3fd5ff613e2860d65e0953446f264b Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 22 Oct 2024 12:13:04 +0300 Subject: [PATCH 088/406] fix(net): Do not use netif_index_to_name Causes error on recent IDF builds --- cores/esp32/IPAddress.cpp | 14 +++++++------- libraries/Network/src/NetworkInterface.cpp | 8 ++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/cores/esp32/IPAddress.cpp b/cores/esp32/IPAddress.cpp index b4fc4c3f7e0..74fabaf0f9c 100644 --- a/cores/esp32/IPAddress.cpp +++ b/cores/esp32/IPAddress.cpp @@ -344,13 +344,13 @@ size_t IPAddress::printTo(Print &p, bool includeZone) const { n += p.print(':'); } } - // add a zone if zone-id is non-zero - if (_zone > 0 && includeZone) { - n += p.print('%'); - char if_name[NETIF_NAMESIZE]; - netif_index_to_name(_zone, if_name); - n += p.print(if_name); - } + // add a zone if zone-id is non-zero (causes exception on recent IDF builds) + // if (_zone > 0 && includeZone) { + // n += p.print('%'); + // char if_name[NETIF_NAMESIZE]; + // netif_index_to_name(_zone, if_name); + // n += p.print(if_name); + // } return n; } diff --git a/libraries/Network/src/NetworkInterface.cpp b/libraries/Network/src/NetworkInterface.cpp index f4bb1d48392..e699d609ca1 100644 --- a/libraries/Network/src/NetworkInterface.cpp +++ b/libraries/Network/src/NetworkInterface.cpp @@ -115,14 +115,10 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void *event_data) { setStatusBits(ESP_NETIF_HAS_LOCAL_IP6_BIT); } #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE - char if_name[NETIF_NAMESIZE] = { - 0, - }; - netif_index_to_name(event->ip6_info.ip.zone, if_name); static const char *addr_types[] = {"UNKNOWN", "GLOBAL", "LINK_LOCAL", "SITE_LOCAL", "UNIQUE_LOCAL", "IPV4_MAPPED_IPV6"}; log_v( - "IF %s Got IPv6: Interface: %d, IP Index: %d, Type: %s, Zone: %d (%s), Address: " IPV6STR, desc(), _interface_id, event->ip_index, addr_types[addr_type], - event->ip6_info.ip.zone, if_name, IPV62STR(event->ip6_info.ip) + "IF %s Got IPv6: Interface: %d, IP Index: %d, Type: %s, Zone: %d, Address: " IPV6STR, desc(), _interface_id, event->ip_index, addr_types[addr_type], + event->ip6_info.ip.zone, IPV62STR(event->ip6_info.ip) ); #endif memcpy(&arduino_event.event_info.got_ip6, event_data, sizeof(ip_event_got_ip6_t)); From 774201ade36955bad468d616170006c8dbdf747f Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 22 Oct 2024 15:19:24 +0300 Subject: [PATCH 089/406] fix(build): Require main component to include all components --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e552299b8aa..5a8955248ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,7 +312,7 @@ endforeach() set(includedirs variants/${CONFIG_ARDUINO_VARIANT}/ cores/esp32/ ${ARDUINO_LIBRARIES_INCLUDEDIRS}) set(srcs ${CORE_SRCS} ${ARDUINO_LIBRARIES_SRCS}) set(priv_includes cores/esp32/libb64) -set(requires spi_flash esp_partition mbedtls wpa_supplicant esp_adc esp_eth http_parser esp_ringbuf esp_driver_gptimer esp_driver_usb_serial_jtag driver espressif__network_provisioning) +set(requires main spi_flash esp_partition mbedtls wpa_supplicant esp_adc esp_eth http_parser esp_ringbuf esp_driver_gptimer esp_driver_usb_serial_jtag driver espressif__network_provisioning) set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support bt esp_hid usb esp_psram ${ARDUINO_LIBRARIES_REQUIRES}) if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_OpenThread) From 16314664269019a57665d221a39e655190224e06 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Tue, 22 Oct 2024 15:55:37 +0300 Subject: [PATCH 090/406] fix(build): Update required components and menu --- CMakeLists.txt | 8 +++++++- Kconfig.projbuild | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a8955248ad..57220990c1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,7 +312,7 @@ endforeach() set(includedirs variants/${CONFIG_ARDUINO_VARIANT}/ cores/esp32/ ${ARDUINO_LIBRARIES_INCLUDEDIRS}) set(srcs ${CORE_SRCS} ${ARDUINO_LIBRARIES_SRCS}) set(priv_includes cores/esp32/libb64) -set(requires main spi_flash esp_partition mbedtls wpa_supplicant esp_adc esp_eth http_parser esp_ringbuf esp_driver_gptimer esp_driver_usb_serial_jtag driver espressif__network_provisioning) +set(requires spi_flash esp_partition mbedtls wpa_supplicant esp_adc esp_eth http_parser esp_ringbuf esp_driver_gptimer esp_driver_usb_serial_jtag driver espressif__network_provisioning) set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support bt esp_hid usb esp_psram ${ARDUINO_LIBRARIES_REQUIRES}) if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_OpenThread) @@ -372,3 +372,9 @@ endif() if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_ArduinoOTA) maybe_add_component(esp_https_ota) endif() +if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_ESP_SR) + maybe_add_component(espressif__esp_sr) +endif() +if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_Matter) + maybe_add_component(espressif__esp_matter) +endif() diff --git a/Kconfig.projbuild b/Kconfig.projbuild index 2085a11ea7d..9966463f8c1 100644 --- a/Kconfig.projbuild +++ b/Kconfig.projbuild @@ -266,6 +266,11 @@ config ARDUINO_SELECTIVE_Wire depends on ARDUINO_SELECTIVE_COMPILATION default y +config ARDUINO_SELECTIVE_ESP_SR + bool "Enable ESP-SR" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + config ARDUINO_SELECTIVE_EEPROM bool "Enable EEPROM" depends on ARDUINO_SELECTIVE_COMPILATION @@ -286,6 +291,11 @@ config ARDUINO_SELECTIVE_Update depends on ARDUINO_SELECTIVE_COMPILATION default y +config ARDUINO_SELECTIVE_Zigbee + bool "Enable Zigbee" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + config ARDUINO_SELECTIVE_FS bool "Enable FS" depends on ARDUINO_SELECTIVE_COMPILATION @@ -358,6 +368,11 @@ config ARDUINO_SELECTIVE_HTTPClient select ARDUINO_SELECTIVE_NetworkClientSecure default y +config ARDUINO_SELECTIVE_Matter + bool "Enable Matter" + depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_Network + default y + config ARDUINO_SELECTIVE_NetBIOS bool "Enable NetBIOS" depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_Network @@ -399,4 +414,19 @@ config ARDUINO_SELECTIVE_SimpleBLE depends on ARDUINO_SELECTIVE_COMPILATION default y +config ARDUINO_SELECTIVE_RainMaker + bool "Enable RainMaker" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_OpenThread + bool "Enable OpenThread" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_Insights + bool "Enable Insights" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + endmenu From aefe8a55d35469a8d8e7022971c89627dc6a1015 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 22 Oct 2024 17:40:11 +0300 Subject: [PATCH 091/406] IDF release/v5.3 59550599 (#10498) --- package/package_esp32_index.template.json | 68 +++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index dc32ddae953..b1c7e23734c 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -42,7 +42,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-707d097b" + "version": "idf-release_v5.3-59550599" }, { "packager": "esp32", @@ -95,63 +95,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-707d097b", + "version": "idf-release_v5.3-59550599", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", - "size": "343601720" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", + "size": "343729890" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", - "size": "343601720" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", + "size": "343729890" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", - "size": "343601720" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", + "size": "343729890" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", - "size": "343601720" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", + "size": "343729890" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", - "size": "343601720" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", + "size": "343729890" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", - "size": "343601720" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", + "size": "343729890" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", - "size": "343601720" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", + "size": "343729890" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-707d097b.zip", - "checksum": "SHA-256:e09d25302eeb1d0e40001280c8fb17e87974496046b929536bb56a50007aa0eb", - "size": "343601720" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", + "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", + "size": "343729890" } ] }, From 0eee5c4a13c6808faef0c9476073d422ed326db4 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 22 Oct 2024 20:17:40 +0300 Subject: [PATCH 092/406] fix(arduino): Move extra_flags to flags (#10493) This will help external library developers --- platform.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/platform.txt b/platform.txt index c97c374e75d..00052ec807e 100644 --- a/platform.txt +++ b/platform.txt @@ -50,10 +50,10 @@ compiler.common_werror_flags=-Werror=return-type # Compile Flags compiler.cpreprocessor.flags="@{compiler.sdk.path}/flags/defines" "-I{build.source.path}" -iprefix "{compiler.sdk.path}/include/" "@{compiler.sdk.path}/flags/includes" "-I{compiler.sdk.path}/{build.memory_type}/include" -compiler.c.flags="@{compiler.sdk.path}/flags/c_flags" {compiler.warning_flags} {compiler.optimization_flags} {compiler.common_werror_flags} -compiler.cpp.flags="@{compiler.sdk.path}/flags/cpp_flags" {compiler.warning_flags} {compiler.optimization_flags} {compiler.common_werror_flags} -compiler.S.flags="@{compiler.sdk.path}/flags/S_flags" {compiler.warning_flags} {compiler.optimization_flags} -compiler.c.elf.flags="@{compiler.sdk.path}/flags/ld_flags" "@{compiler.sdk.path}/flags/ld_scripts" +compiler.c.flags=-MMD -c "@{compiler.sdk.path}/flags/c_flags" {compiler.warning_flags} {compiler.optimization_flags} {compiler.common_werror_flags} +compiler.cpp.flags=-MMD -c "@{compiler.sdk.path}/flags/cpp_flags" {compiler.warning_flags} {compiler.optimization_flags} {compiler.common_werror_flags} +compiler.S.flags=-MMD -c -x assembler-with-cpp "@{compiler.sdk.path}/flags/S_flags" {compiler.warning_flags} {compiler.optimization_flags} +compiler.c.elf.flags="-Wl,--Map={build.path}/{build.project_name}.map" "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-L{compiler.sdk.path}/{build.memory_type}" "-Wl,--wrap=esp_panic_handler" "@{compiler.sdk.path}/flags/ld_flags" "@{compiler.sdk.path}/flags/ld_scripts" compiler.c.elf.libs="@{compiler.sdk.path}/flags/ld_libs" compiler.ar.flags=cr @@ -67,10 +67,10 @@ compiler.ar.cmd={compiler.prefix}gcc-ar compiler.size.cmd={compiler.prefix}size # These can be overridden in platform.local.txt -compiler.c.extra_flags=-MMD -c -compiler.cpp.extra_flags=-MMD -c -compiler.S.extra_flags=-MMD -c -x assembler-with-cpp -compiler.c.elf.extra_flags="-Wl,--Map={build.path}/{build.project_name}.map" "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-L{compiler.sdk.path}/{build.memory_type}" "-Wl,--wrap=esp_panic_handler" +compiler.c.extra_flags= +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.c.elf.extra_flags= compiler.ar.extra_flags= compiler.objcopy.eep.extra_flags= compiler.elf2hex.extra_flags= From 4944dd0df3dcf452b86a72e652ef3bc08eb7da83 Mon Sep 17 00:00:00 2001 From: clashman Date: Tue, 22 Oct 2024 19:22:15 +0200 Subject: [PATCH 093/406] fix(littlefs): Add missing dependency (#10496) --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a858ee79cd..16639e689c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,7 @@ set(ARDUINO_LIBRARY_HTTPUpdate_SRCS libraries/HTTPUpdate/src/HTTPUpdate.cpp) set(ARDUINO_LIBRARY_Insights_SRCS libraries/Insights/src/Insights.cpp) set(ARDUINO_LIBRARY_LittleFS_SRCS libraries/LittleFS/src/LittleFS.cpp) +set(ARDUINO_LIBRARY_LittleFS_REQUIRES esp_littlefs) set(ARDUINO_LIBRARY_NetBIOS_SRCS libraries/NetBIOS/src/NetBIOS.cpp) From 4285912a46d6b5283a55d2342a7ca5ed1b926e15 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 22 Oct 2024 20:40:15 +0300 Subject: [PATCH 094/406] fix(cmake): Use proper name for LittleFS component --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16639e689c7..d7e5ae83b35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,7 @@ set(ARDUINO_LIBRARY_HTTPUpdate_SRCS libraries/HTTPUpdate/src/HTTPUpdate.cpp) set(ARDUINO_LIBRARY_Insights_SRCS libraries/Insights/src/Insights.cpp) set(ARDUINO_LIBRARY_LittleFS_SRCS libraries/LittleFS/src/LittleFS.cpp) -set(ARDUINO_LIBRARY_LittleFS_REQUIRES esp_littlefs) +set(ARDUINO_LIBRARY_LittleFS_REQUIRES joltwallet__littlefs) set(ARDUINO_LIBRARY_NetBIOS_SRCS libraries/NetBIOS/src/NetBIOS.cpp) From dc1a49e6f0c51eeae0179e909cc9cc3afa82d802 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 23 Oct 2024 02:04:03 +0300 Subject: [PATCH 095/406] IDF release/v5.3 (#10503) * fix(psram): Do not disable PSRAM when used as component Information: https://github.com/espressif/arduino-esp32/issues/10500 * IDF release/v5.3 59550599 --- cores/esp32/esp32-hal-psram.h | 3 ++- package/package_esp32_index.template.json | 32 +++++++++++------------ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/cores/esp32/esp32-hal-psram.h b/cores/esp32/esp32-hal-psram.h index e82af1342c2..69c1c625157 100644 --- a/cores/esp32/esp32-hal-psram.h +++ b/cores/esp32/esp32-hal-psram.h @@ -21,7 +21,8 @@ extern "C" { #include "sdkconfig.h" -#ifndef BOARD_HAS_PSRAM +// Clear flags in Arduino IDE when PSRAM is disabled +#if defined(ESP32_ARDUINO_LIB_BUILDER) && !defined(BOARD_HAS_PSRAM) #ifdef CONFIG_SPIRAM_SUPPORT #undef CONFIG_SPIRAM_SUPPORT #endif diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index b1c7e23734c..ad941e841f6 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -101,57 +101,57 @@ "host": "i686-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", - "size": "343729890" + "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", + "size": "343730097" }, { "host": "x86_64-mingw32", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", - "size": "343729890" + "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", + "size": "343730097" }, { "host": "arm64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", - "size": "343729890" + "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", + "size": "343730097" }, { "host": "x86_64-apple-darwin", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", - "size": "343729890" + "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", + "size": "343730097" }, { "host": "x86_64-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", - "size": "343729890" + "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", + "size": "343730097" }, { "host": "i686-pc-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", - "size": "343729890" + "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", + "size": "343730097" }, { "host": "aarch64-linux-gnu", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", - "size": "343729890" + "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", + "size": "343730097" }, { "host": "arm-linux-gnueabihf", "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d8edd2fcf990c5af4627c9446efd8c5badb34cfcccfcc3b63bb117d1da77bfae", - "size": "343729890" + "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", + "size": "343730097" } ] }, From 0f5219df0e3222d9188334187b6bd0f11b7e2316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 23 Oct 2024 09:24:36 +0200 Subject: [PATCH 096/406] fix(ci): Get correct file for the diff (#10507) --- .github/scripts/find_new_boards.sh | 31 +++++++++++++++--------------- .github/workflows/boards.yml | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/scripts/find_new_boards.sh b/.github/scripts/find_new_boards.sh index 083f1448e83..706676b4a4c 100755 --- a/.github/scripts/find_new_boards.sh +++ b/.github/scripts/find_new_boards.sh @@ -2,30 +2,31 @@ # Get inputs from command owner_repository=$1 -pr_number=$2 +base_ref=$2 -url="https://api.github.com/repos/$owner_repository/pulls/$pr_number/files" -echo $url +# Download the boards.txt file from the base branch +curl -L -o boards_base.txt https://raw.githubusercontent.com/$owner_repository/$base_ref/boards.txt -# Get changes in boards.txt file from PR -Boards_modified_url=$(curl -s $url | jq -r '.[] | select(.filename == "boards.txt") | .raw_url') +# Compare boards.txt file in the repo with the modified file from PR +diff=$(diff -u boards_base.txt boards.txt) -# Echo the modified boards.txt file URL -echo "Modified boards.txt file URL:" -echo $Boards_modified_url - -# Download the modified boards.txt file -curl -L -o boards_pr.txt $Boards_modified_url - -# Compare boards.txt file in the repo with the modified file -diff=$(diff -u boards.txt boards_pr.txt) +# Check if the diff is empty +if [ -z "$diff" ] +then + echo "No changes in boards.txt file" + echo "FQBNS=" + exit 0 +fi # Extract added or modified lines (lines starting with '+' or '-') modified_lines=$(echo "$diff" | grep -E '^[+-][^+-]') +# Print the modified lines for debugging +echo "Modified lines:" +echo "$modified_lines" + boards_array=() previous_board="" -file="boards.txt" # Extract board names from the modified lines, and add them to the boards_array while read -r line diff --git a/.github/workflows/boards.yml b/.github/workflows/boards.yml index 8d5868b083b..a14f57508c6 100644 --- a/.github/workflows/boards.yml +++ b/.github/workflows/boards.yml @@ -29,7 +29,7 @@ jobs: - name: Get board name run: - bash .github/scripts/find_new_boards.sh ${{ github.repository }} ${{github.event.number}} + bash .github/scripts/find_new_boards.sh ${{ github.repository }} ${{github.base_ref}} test-boards: needs: find-boards From a0139bc37d63efe28fabb2ef57d1e369b4ad38c7 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Wed, 23 Oct 2024 05:45:30 -0300 Subject: [PATCH 097/406] fix(tests): Add missing files to compilation tests (#10501) * fix(tests): Add CMakeLists file to compilation tests * fix(tests): Add variant files that are used in compilation * fix(c2): Move C2 as it is only tested as component --------- Co-authored-by: Me No Dev --- .github/workflows/push.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 0f76fe81fb8..19e53b844f2 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -21,12 +21,20 @@ on: - 'idf_component.yml' - 'Kconfig.projbuild' - 'package.json' + - 'CMakeLists.txt' - '.github/workflows/push.yml' - '.github/scripts/**' - '!.github/scripts/find_*' - '!.github/scripts/on-release.sh' - '!.github/scripts/tests_*' - '!.github/scripts/upload_*' + - "variants/esp32/**/*" + - "variants/esp32s2/**/*" + - "variants/esp32s3/**/*" + - "variants/esp32c2/**/*" + - "variants/esp32c3/**/*" + - "variants/esp32c6/**/*" + - "variants/esp32h2/**/*" concurrency: group: build-${{github.event.pull_request.number || github.ref}} @@ -74,6 +82,12 @@ jobs: - '!tools/platformio-build.py' - 'platform.txt' - 'programmers.txt' + - "variants/esp32/**/*" + - "variants/esp32s2/**/*" + - "variants/esp32s3/**/*" + - "variants/esp32c3/**/*" + - "variants/esp32c6/**/*" + - "variants/esp32h2/**/*" libraries: - 'libraries/**/examples/**' - 'libraries/**/src/**' @@ -92,6 +106,8 @@ jobs: idf: - 'idf_component.yml' - 'Kconfig.projbuild' + - 'CMakeLists.txt' + - "variants/esp32c2/**/*" platformio: - 'package.json' - '.github/scripts/install-platformio-esp32.sh' From 1756bd567cca0c25cc155999bcc15387099ceb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Wed, 23 Oct 2024 10:46:04 +0200 Subject: [PATCH 098/406] fix(zigbee): Enable internal pull-up resistor (#10491) Enable the internal pull-up resistor for BUTTON_PIN --- .../Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino | 2 +- .../Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino | 2 +- .../Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino | 2 +- .../Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino | 2 +- .../Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino index 1ce9ff56816..01e8c24900f 100644 --- a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino @@ -65,7 +65,7 @@ void setup() { rgbLedWrite(LED_PIN, 0, 0, 0); // Init button for factory reset - pinMode(BUTTON_PIN, INPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); // Set callback function for light change zbColorLight.onLightChange(setRGBLight); diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino index a494623e436..0514464e8e9 100644 --- a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino +++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino @@ -54,7 +54,7 @@ void setup() { } //Init button switch - pinMode(SWITCH_PIN, INPUT); + pinMode(SWITCH_PIN, INPUT_PULLUP); //Optional: set Zigbee device name and model zbSwitch.setManufacturerAndModel("Espressif", "ZigbeeSwitch"); diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino b/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino index 2f13357a156..e0bc3747eb3 100644 --- a/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino +++ b/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino @@ -51,7 +51,7 @@ void setup() { digitalWrite(LED_PIN, LOW); // Init button for factory reset - pinMode(BUTTON_PIN, INPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); //Optional: set Zigbee device name and model zbLight.setManufacturerAndModel("Espressif", "ZBLightBulb"); diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino index 92249e980ab..b614b136bef 100644 --- a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino @@ -59,7 +59,7 @@ void setup() { } // Init button switch - pinMode(BUTTON_PIN, INPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); // Optional: set Zigbee device name and model zbTempSensor.setManufacturerAndModel("Espressif", "ZigbeeTempSensor"); diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino index 8f4ea0b543d..ac7b023d6d9 100644 --- a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino @@ -65,7 +65,7 @@ void setup() { } // Init button switch - pinMode(BUTTON_PIN, INPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); // Set callback functions for temperature and configuration receive zbThermostat.onTempRecieve(recieveSensorTemp); From bcc357c0cac2710d41820961167e8383ecb1aadc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:47:50 +0200 Subject: [PATCH 099/406] fix(ci): Boards test set fail-fast to false (#10508) --- .github/workflows/boards.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/boards.yml b/.github/workflows/boards.yml index a14f57508c6..a309e4ed2ce 100644 --- a/.github/workflows/boards.yml +++ b/.github/workflows/boards.yml @@ -42,6 +42,7 @@ jobs: name: "espressif:esp32" strategy: + fail-fast: false matrix: ${{ fromJson(needs.find-boards.outputs.fqbns) }} steps: From 3502b9c7a9c9fcecc51c1f40ea0180a8563f44cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E4=B9=9D?= <153150268+Sail-211010@users.noreply.github.com> Date: Wed, 23 Oct 2024 20:16:12 +0800 Subject: [PATCH 100/406] Add multiple boards of the Waveshare ESP32-S3-Touch-LCD-1.46 type (#10482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Delete boards.txt Delete old files * Add files via upload Add new board * Add files via upload Add new board * Delete boards.txt Delete old files, modify the definition of the case error * Add files via upload Modify the definition of the case error * ci(pre-commit): Apply automatic fixes * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: Jan Procházka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Co-authored-by: Me No Dev Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> --- boards.txt | 1899 +++++++++++++++++ .../waveshare_esp32_s3_lcd_146/pins_arduino.h | 64 + .../waveshare_esp32_s3_lcd_147/pins_arduino.h | 64 + .../waveshare_esp32_s3_lcd_185/pins_arduino.h | 64 + .../pins_arduino.h | 64 + .../pins_arduino.h | 64 + .../pins_arduino.h | 64 + .../pins_arduino.h | 64 + .../pins_arduino.h | 64 + 9 files changed, 2411 insertions(+) create mode 100644 variants/waveshare_esp32_s3_lcd_146/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_lcd_147/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_lcd_185/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_relay_6ch/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_146/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_185_box/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_21/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_lcd_28/pins_arduino.h diff --git a/boards.txt b/boards.txt index 74d709ec1e1..8d4cc529ed7 100644 --- a/boards.txt +++ b/boards.txt @@ -44367,3 +44367,1902 @@ cezerio_dev_esp32c6.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP cezerio_dev_esp32c6.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port ############################################################## + +waveshare_esp32_s3_lcd_185.name=Waveshare ESP32-S3-LCD-1.85 +waveshare_esp32_s3_lcd_185.vid.0=0x303a +waveshare_esp32_s3_lcd_185.pid.0=0x8242 +waveshare_esp32_s3_lcd_185.upload_port.0.vid=0x303a +waveshare_esp32_s3_lcd_185.upload_port.0.pid=0x8242 + +waveshare_esp32_s3_lcd_185.bootloader.tool=esptool_py +waveshare_esp32_s3_lcd_185.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_lcd_185.upload.tool=esptool_py +waveshare_esp32_s3_lcd_185.upload.tool.default=esptool_py +waveshare_esp32_s3_lcd_185.upload.tool.network=esp_ota + +waveshare_esp32_s3_lcd_185.upload.maximum_size=1310720 +waveshare_esp32_s3_lcd_185.upload.maximum_data_size=327680 +waveshare_esp32_s3_lcd_185.upload.flags= +waveshare_esp32_s3_lcd_185.upload.extra_flags= +waveshare_esp32_s3_lcd_185.upload.use_1200bps_touch=false +waveshare_esp32_s3_lcd_185.upload.wait_for_upload_port=false + +waveshare_esp32_s3_lcd_185.serial.disableDTR=false +waveshare_esp32_s3_lcd_185.serial.disableRTS=false + +waveshare_esp32_s3_lcd_185.build.tarch=xtensa +waveshare_esp32_s3_lcd_185.build.bootloader_addr=0x0 +waveshare_esp32_s3_lcd_185.build.target=esp32s3 +waveshare_esp32_s3_lcd_185.build.mcu=esp32s3 +waveshare_esp32_s3_lcd_185.build.core=esp32 +waveshare_esp32_s3_lcd_185.build.variant=waveshare_esp32_s3_lcd_185 +waveshare_esp32_s3_lcd_185.build.board=WAVESHARE_ESP32_S3_LCD_185 + +waveshare_esp32_s3_lcd_185.build.usb_mode=1 +waveshare_esp32_s3_lcd_185.build.cdc_on_boot=0 +waveshare_esp32_s3_lcd_185.build.msc_on_boot=0 +waveshare_esp32_s3_lcd_185.build.dfu_on_boot=0 +waveshare_esp32_s3_lcd_185.build.f_cpu=240000000L +waveshare_esp32_s3_lcd_185.build.flash_size=16MB +waveshare_esp32_s3_lcd_185.build.flash_freq=120m +waveshare_esp32_s3_lcd_185.build.flash_mode=qio +waveshare_esp32_s3_lcd_185.build.boot=qio +waveshare_esp32_s3_lcd_185.build.boot_freq=80m +waveshare_esp32_s3_lcd_185.build.partitions=default +waveshare_esp32_s3_lcd_185.build.defines= +waveshare_esp32_s3_lcd_185.build.loop_core= +waveshare_esp32_s3_lcd_185.build.event_core= +waveshare_esp32_s3_lcd_185.build.psram_type=opi +waveshare_esp32_s3_lcd_185.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_lcd_185.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_lcd_185.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_lcd_185.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_lcd_185.menu.PSRAM.enabled.build.psram_type=opi +waveshare_esp32_s3_lcd_185.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_lcd_185.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_lcd_185.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_lcd_185.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_lcd_185.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_lcd_185.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_lcd_185.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_lcd_185.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_lcd_185.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_lcd_185.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_lcd_185.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_lcd_185.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_lcd_185.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_lcd_185.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_lcd_185.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_lcd_185.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_lcd_185.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_lcd_185.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_lcd_185.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_lcd_185.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 +waveshare_esp32_s3_lcd_185.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_lcd_185.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 + +waveshare_esp32_s3_lcd_185.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_lcd_185.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_lcd_185.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_lcd_185.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_lcd_185.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_lcd_185.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_lcd_185.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_lcd_185.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_lcd_185.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_lcd_185.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_lcd_185.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_lcd_185.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_lcd_185.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_lcd_185.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_lcd_185.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_lcd_185.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_lcd_185.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_lcd_185.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_lcd_185.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_lcd_185.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_lcd_185.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_lcd_185.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_lcd_185.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_lcd_185.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_lcd_185.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_lcd_185.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_lcd_185.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_lcd_185.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_lcd_185.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_lcd_185.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_lcd_185.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_lcd_185.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_lcd_185.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_lcd_185.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_lcd_185.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_lcd_185.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_lcd_185.menu.DebugLevel.none=None +waveshare_esp32_s3_lcd_185.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_lcd_185.menu.DebugLevel.error=Error +waveshare_esp32_s3_lcd_185.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_lcd_185.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_lcd_185.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_lcd_185.menu.DebugLevel.info=Info +waveshare_esp32_s3_lcd_185.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_lcd_185.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_lcd_185.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_lcd_185.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_lcd_185.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_lcd_185.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_lcd_185.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_lcd_185.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_lcd_185.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_lcd_185.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_lcd_185.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_lcd_185.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_lcd_185.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_lcd_185.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_lcd_185.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## + +waveshare_esp32_s3_touch_lcd_146.name=Waveshare ESP32-S3-Touch-LCD-1.46 +waveshare_esp32_s3_touch_lcd_146.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_146.pid.0=0x8242 +waveshare_esp32_s3_touch_lcd_146.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_146.upload_port.0.pid=0x8242 + +waveshare_esp32_s3_touch_lcd_146.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_146.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_146.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_146.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_146.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_146.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_146.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_146.upload.flags= +waveshare_esp32_s3_touch_lcd_146.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_146.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_146.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_146.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_146.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_146.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_146.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_146.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_146.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_146.build.core=esp32 +waveshare_esp32_s3_touch_lcd_146.build.variant=waveshare_esp32_s3_touch_lcd_146 +waveshare_esp32_s3_touch_lcd_146.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_146 + +waveshare_esp32_s3_touch_lcd_146.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_146.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_146.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_146.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_146.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_146.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_146.build.flash_freq=120m +waveshare_esp32_s3_touch_lcd_146.build.flash_mode=qio +waveshare_esp32_s3_touch_lcd_146.build.boot=qio +waveshare_esp32_s3_touch_lcd_146.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_146.build.partitions=default +waveshare_esp32_s3_touch_lcd_146.build.defines= +waveshare_esp32_s3_touch_lcd_146.build.loop_core= +waveshare_esp32_s3_touch_lcd_146.build.event_core= +waveshare_esp32_s3_touch_lcd_146.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_146.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_touch_lcd_146.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_touch_lcd_146.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_146.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_146.menu.PSRAM.enabled.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_146.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_146.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_146.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_146.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_146.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_146.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_146.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_146.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_146.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_146.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 +waveshare_esp32_s3_touch_lcd_146.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_146.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 + +waveshare_esp32_s3_touch_lcd_146.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_146.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_146.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_146.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_146.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_146.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_146.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_146.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_146.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_146.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_146.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_146.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_146.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_146.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_146.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_146.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_146.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_146.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_146.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_146.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_146.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_146.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_146.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_146.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_146.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_146.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_146.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_146.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_146.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_146.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_touch_lcd_146.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_touch_lcd_146.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_touch_lcd_146.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_touch_lcd_146.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_touch_lcd_146.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_touch_lcd_146.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## + +waveshare_esp32_s3_lcd_146.name=Waveshare ESP32-S3-LCD-1.46 +waveshare_esp32_s3_lcd_146.vid.0=0x303a +waveshare_esp32_s3_lcd_146.pid.0=0x8242 +waveshare_esp32_s3_lcd_146.upload_port.0.vid=0x303a +waveshare_esp32_s3_lcd_146.upload_port.0.pid=0x8242 + +waveshare_esp32_s3_lcd_146.bootloader.tool=esptool_py +waveshare_esp32_s3_lcd_146.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_lcd_146.upload.tool=esptool_py +waveshare_esp32_s3_lcd_146.upload.tool.default=esptool_py +waveshare_esp32_s3_lcd_146.upload.tool.network=esp_ota + +waveshare_esp32_s3_lcd_146.upload.maximum_size=1310720 +waveshare_esp32_s3_lcd_146.upload.maximum_data_size=327680 +waveshare_esp32_s3_lcd_146.upload.flags= +waveshare_esp32_s3_lcd_146.upload.extra_flags= +waveshare_esp32_s3_lcd_146.upload.use_1200bps_touch=false +waveshare_esp32_s3_lcd_146.upload.wait_for_upload_port=false + +waveshare_esp32_s3_lcd_146.serial.disableDTR=false +waveshare_esp32_s3_lcd_146.serial.disableRTS=false + +waveshare_esp32_s3_lcd_146.build.tarch=xtensa +waveshare_esp32_s3_lcd_146.build.bootloader_addr=0x0 +waveshare_esp32_s3_lcd_146.build.target=esp32s3 +waveshare_esp32_s3_lcd_146.build.mcu=esp32s3 +waveshare_esp32_s3_lcd_146.build.core=esp32 +waveshare_esp32_s3_lcd_146.build.variant=waveshare_esp32_s3_lcd_146 +waveshare_esp32_s3_lcd_146.build.board=WAVESHARE_ESP32_S3_LCD_146 + +waveshare_esp32_s3_lcd_146.build.usb_mode=1 +waveshare_esp32_s3_lcd_146.build.cdc_on_boot=0 +waveshare_esp32_s3_lcd_146.build.msc_on_boot=0 +waveshare_esp32_s3_lcd_146.build.dfu_on_boot=0 +waveshare_esp32_s3_lcd_146.build.f_cpu=240000000L +waveshare_esp32_s3_lcd_146.build.flash_size=16MB +waveshare_esp32_s3_lcd_146.build.flash_freq=120m +waveshare_esp32_s3_lcd_146.build.flash_mode=qio +waveshare_esp32_s3_lcd_146.build.boot=qio +waveshare_esp32_s3_lcd_146.build.boot_freq=80m +waveshare_esp32_s3_lcd_146.build.partitions=default +waveshare_esp32_s3_lcd_146.build.defines= +waveshare_esp32_s3_lcd_146.build.loop_core= +waveshare_esp32_s3_lcd_146.build.event_core= +waveshare_esp32_s3_lcd_146.build.psram_type=opi +waveshare_esp32_s3_lcd_146.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_lcd_146.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_lcd_146.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_lcd_146.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_lcd_146.menu.PSRAM.enabled.build.psram_type=opi +waveshare_esp32_s3_lcd_146.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_lcd_146.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_lcd_146.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_lcd_146.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_lcd_146.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_lcd_146.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_lcd_146.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_lcd_146.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_lcd_146.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_lcd_146.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_lcd_146.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_lcd_146.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_lcd_146.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_lcd_146.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_lcd_146.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_lcd_146.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_lcd_146.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_lcd_146.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_lcd_146.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_lcd_146.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 +waveshare_esp32_s3_lcd_146.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_lcd_146.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 + +waveshare_esp32_s3_lcd_146.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_lcd_146.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_lcd_146.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_lcd_146.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_lcd_146.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_lcd_146.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_lcd_146.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_lcd_146.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_lcd_146.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_lcd_146.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_lcd_146.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_lcd_146.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_lcd_146.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_lcd_146.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_lcd_146.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_lcd_146.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_lcd_146.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_lcd_146.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_lcd_146.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_lcd_146.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_lcd_146.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_lcd_146.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_lcd_146.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_lcd_146.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_lcd_146.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_lcd_146.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_lcd_146.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_lcd_146.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_lcd_146.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_lcd_146.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_lcd_146.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_lcd_146.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_lcd_146.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_lcd_146.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_lcd_146.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_lcd_146.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_lcd_146.menu.DebugLevel.none=None +waveshare_esp32_s3_lcd_146.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_lcd_146.menu.DebugLevel.error=Error +waveshare_esp32_s3_lcd_146.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_lcd_146.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_lcd_146.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_lcd_146.menu.DebugLevel.info=Info +waveshare_esp32_s3_lcd_146.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_lcd_146.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_lcd_146.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_lcd_146.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_lcd_146.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_lcd_146.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_lcd_146.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_lcd_146.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_lcd_146.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_lcd_146.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_lcd_146.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_lcd_146.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_lcd_146.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_lcd_146.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_lcd_146.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## + +waveshare_esp32_s3_touch_lcd_185_box.name=Waveshare ESP32-S3-Touch-LCD-1.85-BOX +waveshare_esp32_s3_touch_lcd_185_box.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_185_box.pid.0=0x8242 +waveshare_esp32_s3_touch_lcd_185_box.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_185_box.upload_port.0.pid=0x8242 + +waveshare_esp32_s3_touch_lcd_185_box.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_185_box.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_185_box.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_185_box.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_185_box.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_185_box.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_185_box.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_185_box.upload.flags= +waveshare_esp32_s3_touch_lcd_185_box.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_185_box.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_185_box.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_185_box.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_185_box.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_185_box.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_185_box.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_185_box.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_185_box.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_185_box.build.core=esp32 +waveshare_esp32_s3_touch_lcd_185_box.build.variant=waveshare_esp32_s3_touch_lcd_185_box +waveshare_esp32_s3_touch_lcd_185_box.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_185_BOX + +waveshare_esp32_s3_touch_lcd_185_box.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_185_box.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_185_box.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_185_box.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_185_box.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_185_box.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_185_box.build.flash_freq=120m +waveshare_esp32_s3_touch_lcd_185_box.build.flash_mode=qio +waveshare_esp32_s3_touch_lcd_185_box.build.boot=qio +waveshare_esp32_s3_touch_lcd_185_box.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_185_box.build.partitions=default +waveshare_esp32_s3_touch_lcd_185_box.build.defines= +waveshare_esp32_s3_touch_lcd_185_box.build.loop_core= +waveshare_esp32_s3_touch_lcd_185_box.build.event_core= +waveshare_esp32_s3_touch_lcd_185_box.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_185_box.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_touch_lcd_185_box.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_touch_lcd_185_box.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_185_box.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_185_box.menu.PSRAM.enabled.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_185_box.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_185_box.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_185_box.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_185_box.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_185_box.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_185_box.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_185_box.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_185_box.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_185_box.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_185_box.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 +waveshare_esp32_s3_touch_lcd_185_box.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_185_box.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 + +waveshare_esp32_s3_touch_lcd_185_box.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_185_box.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_185_box.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_185_box.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_185_box.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_185_box.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_185_box.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_185_box.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_185_box.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_185_box.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_185_box.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_185_box.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_185_box.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_185_box.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_185_box.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_185_box.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_185_box.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_185_box.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_185_box.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_185_box.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_185_box.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_185_box.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_185_box.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_185_box.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_touch_lcd_185_box.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_touch_lcd_185_box.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_touch_lcd_185_box.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_touch_lcd_185_box.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_touch_lcd_185_box.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_touch_lcd_185_box.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## + +waveshare_esp32_s3_lcd_147.name=Waveshare ESP32-S3-LCD-1.47 +waveshare_esp32_s3_lcd_147.vid.0=0x303a +waveshare_esp32_s3_lcd_147.pid.0=0x8242 +waveshare_esp32_s3_lcd_147.upload_port.0.vid=0x303a +waveshare_esp32_s3_lcd_147.upload_port.0.pid=0x8242 + +waveshare_esp32_s3_lcd_147.bootloader.tool=esptool_py +waveshare_esp32_s3_lcd_147.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_lcd_147.upload.tool=esptool_py +waveshare_esp32_s3_lcd_147.upload.tool.default=esptool_py +waveshare_esp32_s3_lcd_147.upload.tool.network=esp_ota + +waveshare_esp32_s3_lcd_147.upload.maximum_size=1310720 +waveshare_esp32_s3_lcd_147.upload.maximum_data_size=327680 +waveshare_esp32_s3_lcd_147.upload.flags= +waveshare_esp32_s3_lcd_147.upload.extra_flags= +waveshare_esp32_s3_lcd_147.upload.use_1200bps_touch=false +waveshare_esp32_s3_lcd_147.upload.wait_for_upload_port=false + +waveshare_esp32_s3_lcd_147.serial.disableDTR=false +waveshare_esp32_s3_lcd_147.serial.disableRTS=false + +waveshare_esp32_s3_lcd_147.build.tarch=xtensa +waveshare_esp32_s3_lcd_147.build.bootloader_addr=0x0 +waveshare_esp32_s3_lcd_147.build.target=esp32s3 +waveshare_esp32_s3_lcd_147.build.mcu=esp32s3 +waveshare_esp32_s3_lcd_147.build.core=esp32 +waveshare_esp32_s3_lcd_147.build.variant=waveshare_esp32_s3_lcd_147 +waveshare_esp32_s3_lcd_147.build.board=WAVESHARE_ESP32_S3_LCD_147 + +waveshare_esp32_s3_lcd_147.build.usb_mode=1 +waveshare_esp32_s3_lcd_147.build.cdc_on_boot=0 +waveshare_esp32_s3_lcd_147.build.msc_on_boot=0 +waveshare_esp32_s3_lcd_147.build.dfu_on_boot=0 +waveshare_esp32_s3_lcd_147.build.f_cpu=240000000L +waveshare_esp32_s3_lcd_147.build.flash_size=16MB +waveshare_esp32_s3_lcd_147.build.flash_freq=80m +waveshare_esp32_s3_lcd_147.build.flash_mode=qio +waveshare_esp32_s3_lcd_147.build.boot=qio +waveshare_esp32_s3_lcd_147.build.boot_freq=80m +waveshare_esp32_s3_lcd_147.build.partitions=default +waveshare_esp32_s3_lcd_147.build.defines= +waveshare_esp32_s3_lcd_147.build.loop_core= +waveshare_esp32_s3_lcd_147.build.event_core= +waveshare_esp32_s3_lcd_147.build.psram_type=opi +waveshare_esp32_s3_lcd_147.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_lcd_147.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_lcd_147.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_lcd_147.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_lcd_147.menu.PSRAM.enabled.build.psram_type=opi +waveshare_esp32_s3_lcd_147.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_lcd_147.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_lcd_147.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_lcd_147.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_lcd_147.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_lcd_147.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_lcd_147.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_lcd_147.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_lcd_147.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_lcd_147.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_lcd_147.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_lcd_147.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_lcd_147.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_lcd_147.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_lcd_147.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_lcd_147.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_lcd_147.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_lcd_147.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_lcd_147.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_lcd_147.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_lcd_147.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_lcd_147.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_lcd_147.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_lcd_147.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_lcd_147.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_lcd_147.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_lcd_147.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_lcd_147.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_lcd_147.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_lcd_147.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_lcd_147.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_lcd_147.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_lcd_147.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_lcd_147.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_lcd_147.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_lcd_147.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_lcd_147.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_lcd_147.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_lcd_147.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_lcd_147.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_lcd_147.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_lcd_147.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_lcd_147.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_lcd_147.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_lcd_147.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_lcd_147.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_lcd_147.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_lcd_147.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_lcd_147.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_lcd_147.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_lcd_147.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_lcd_147.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_lcd_147.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_lcd_147.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_lcd_147.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_lcd_147.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_lcd_147.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_lcd_147.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_lcd_147.menu.DebugLevel.none=None +waveshare_esp32_s3_lcd_147.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_lcd_147.menu.DebugLevel.error=Error +waveshare_esp32_s3_lcd_147.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_lcd_147.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_lcd_147.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_lcd_147.menu.DebugLevel.info=Info +waveshare_esp32_s3_lcd_147.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_lcd_147.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_lcd_147.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_lcd_147.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_lcd_147.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_lcd_147.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_lcd_147.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_lcd_147.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_lcd_147.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_lcd_147.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_lcd_147.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_lcd_147.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_lcd_147.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_lcd_147.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_lcd_147.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## + +waveshare_esp32_s3_touch_lcd_21.name=Waveshare ESP32-S3-Touch-LCD-2.1 +waveshare_esp32_s3_touch_lcd_21.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_21.pid.0=0x8242 +waveshare_esp32_s3_touch_lcd_21.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_21.upload_port.0.pid=0x8242 + +waveshare_esp32_s3_touch_lcd_21.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_21.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_21.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_21.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_21.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_21.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_21.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_21.upload.flags= +waveshare_esp32_s3_touch_lcd_21.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_21.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_21.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_21.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_21.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_21.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_21.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_21.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_21.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_21.build.core=esp32 +waveshare_esp32_s3_touch_lcd_21.build.variant=waveshare_esp32_s3_touch_lcd_21 +waveshare_esp32_s3_touch_lcd_21.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_21 + +waveshare_esp32_s3_touch_lcd_21.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_21.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_21.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_21.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_21.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_21.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_21.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_21.build.flash_mode=qio +waveshare_esp32_s3_touch_lcd_21.build.boot=qio +waveshare_esp32_s3_touch_lcd_21.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_21.build.partitions=default +waveshare_esp32_s3_touch_lcd_21.build.defines= +waveshare_esp32_s3_touch_lcd_21.build.loop_core= +waveshare_esp32_s3_touch_lcd_21.build.event_core= +waveshare_esp32_s3_touch_lcd_21.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_21.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_touch_lcd_21.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_touch_lcd_21.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_21.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_21.menu.PSRAM.enabled.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_21.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_21.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_21.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_21.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_21.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_21.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_21.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_21.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_21.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_21.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_21.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_21.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_21.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_21.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_21.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_21.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_21.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_21.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_21.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_21.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_21.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_21.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_21.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_21.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_21.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_21.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_21.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_21.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_21.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_21.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_21.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_21.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_21.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_21.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_21.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_21.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_21.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_21.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_21.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_21.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_21.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_21.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_touch_lcd_21.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_touch_lcd_21.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_touch_lcd_21.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_touch_lcd_21.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_touch_lcd_21.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_touch_lcd_21.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## + +waveshare_esp32_s3_touch_lcd_28.name=Waveshare ESP32-S3-Touch-LCD-2.8 +waveshare_esp32_s3_touch_lcd_28.vid.0=0x303a +waveshare_esp32_s3_touch_lcd_28.pid.0=0x8242 +waveshare_esp32_s3_touch_lcd_28.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_lcd_28.upload_port.0.pid=0x8242 + +waveshare_esp32_s3_touch_lcd_28.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_lcd_28.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_lcd_28.upload.tool=esptool_py +waveshare_esp32_s3_touch_lcd_28.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_lcd_28.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_lcd_28.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_28.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_lcd_28.upload.flags= +waveshare_esp32_s3_touch_lcd_28.upload.extra_flags= +waveshare_esp32_s3_touch_lcd_28.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_28.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_lcd_28.serial.disableDTR=false +waveshare_esp32_s3_touch_lcd_28.serial.disableRTS=false + +waveshare_esp32_s3_touch_lcd_28.build.tarch=xtensa +waveshare_esp32_s3_touch_lcd_28.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_lcd_28.build.target=esp32s3 +waveshare_esp32_s3_touch_lcd_28.build.mcu=esp32s3 +waveshare_esp32_s3_touch_lcd_28.build.core=esp32 +waveshare_esp32_s3_touch_lcd_28.build.variant=waveshare_esp32_s3_touch_lcd_28 +waveshare_esp32_s3_touch_lcd_28.build.board=WAVESHARE_ESP32_S3_TOUCH_LCD_28 + +waveshare_esp32_s3_touch_lcd_28.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_28.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_28.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_28.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_28.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_28.build.flash_size=16MB +waveshare_esp32_s3_touch_lcd_28.build.flash_freq=120m +waveshare_esp32_s3_touch_lcd_28.build.flash_mode=qio +waveshare_esp32_s3_touch_lcd_28.build.boot=qio +waveshare_esp32_s3_touch_lcd_28.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_28.build.partitions=default +waveshare_esp32_s3_touch_lcd_28.build.defines= +waveshare_esp32_s3_touch_lcd_28.build.loop_core= +waveshare_esp32_s3_touch_lcd_28.build.event_core= +waveshare_esp32_s3_touch_lcd_28.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_28.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_touch_lcd_28.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_touch_lcd_28.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_lcd_28.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_lcd_28.menu.PSRAM.enabled.build.psram_type=opi +waveshare_esp32_s3_touch_lcd_28.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_lcd_28.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_lcd_28.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_touch_lcd_28.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_touch_lcd_28.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_28.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_lcd_28.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_28.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_lcd_28.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_lcd_28.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 +waveshare_esp32_s3_touch_lcd_28.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_lcd_28.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 + +waveshare_esp32_s3_touch_lcd_28.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_lcd_28.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_lcd_28.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_lcd_28.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_lcd_28.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_28.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_lcd_28.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_lcd_28.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_28.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_28.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_lcd_28.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_28.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_lcd_28.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_lcd_28.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_lcd_28.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_lcd_28.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_lcd_28.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_lcd_28.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_lcd_28.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_lcd_28.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_lcd_28.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_lcd_28.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_lcd_28.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_lcd_28.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_lcd_28.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_lcd_28.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_lcd_28.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_lcd_28.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_lcd_28.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_lcd_28.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_touch_lcd_28.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_touch_lcd_28.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_touch_lcd_28.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_touch_lcd_28.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_touch_lcd_28.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_touch_lcd_28.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## + +waveshare_esp32_s3_relay_6ch.name=Waveshare ESP32-S3-Relay-6CH +waveshare_esp32_s3_relay_6ch.vid.0=0x303a +waveshare_esp32_s3_relay_6ch.pid.0=0x8242 +waveshare_esp32_s3_relay_6ch.upload_port.0.vid=0x303a +waveshare_esp32_s3_relay_6ch.upload_port.0.pid=0x8242 + +waveshare_esp32_s3_relay_6ch.bootloader.tool=esptool_py +waveshare_esp32_s3_relay_6ch.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_relay_6ch.upload.tool=esptool_py +waveshare_esp32_s3_relay_6ch.upload.tool.default=esptool_py +waveshare_esp32_s3_relay_6ch.upload.tool.network=esp_ota + +waveshare_esp32_s3_relay_6ch.upload.maximum_size=1310720 +waveshare_esp32_s3_relay_6ch.upload.maximum_data_size=327680 +waveshare_esp32_s3_relay_6ch.upload.flags= +waveshare_esp32_s3_relay_6ch.upload.extra_flags= +waveshare_esp32_s3_relay_6ch.upload.use_1200bps_touch=false +waveshare_esp32_s3_relay_6ch.upload.wait_for_upload_port=false + +waveshare_esp32_s3_relay_6ch.serial.disableDTR=false +waveshare_esp32_s3_relay_6ch.serial.disableRTS=false + +waveshare_esp32_s3_relay_6ch.build.tarch=xtensa +waveshare_esp32_s3_relay_6ch.build.bootloader_addr=0x0 +waveshare_esp32_s3_relay_6ch.build.target=esp32s3 +waveshare_esp32_s3_relay_6ch.build.mcu=esp32s3 +waveshare_esp32_s3_relay_6ch.build.core=esp32 +waveshare_esp32_s3_relay_6ch.build.variant=waveshare_esp32_s3_relay_6ch +waveshare_esp32_s3_relay_6ch.build.board=WAVESHARE_ESP32_S3_RELAY_6CH + +waveshare_esp32_s3_relay_6ch.build.usb_mode=1 +waveshare_esp32_s3_relay_6ch.build.cdc_on_boot=0 +waveshare_esp32_s3_relay_6ch.build.msc_on_boot=0 +waveshare_esp32_s3_relay_6ch.build.dfu_on_boot=0 +waveshare_esp32_s3_relay_6ch.build.f_cpu=240000000L +waveshare_esp32_s3_relay_6ch.build.flash_size=8MB +waveshare_esp32_s3_relay_6ch.build.flash_freq=80m +waveshare_esp32_s3_relay_6ch.build.flash_mode=qio +waveshare_esp32_s3_relay_6ch.build.boot=qio +waveshare_esp32_s3_relay_6ch.build.boot_freq=80m +waveshare_esp32_s3_relay_6ch.build.partitions=default +waveshare_esp32_s3_relay_6ch.build.defines= +waveshare_esp32_s3_relay_6ch.build.loop_core= +waveshare_esp32_s3_relay_6ch.build.event_core= +waveshare_esp32_s3_relay_6ch.build.psram_type= +waveshare_esp32_s3_relay_6ch.build.memory_type={build.boot}_{build.psram_type} + +## IDE 2.0 Seems to not update the value +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.default=Disabled +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg +waveshare_esp32_s3_relay_6ch.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_s3_relay_6ch.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_relay_6ch.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_relay_6ch.menu.PSRAM.disabled.build.psram_type=qspi + +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_relay_6ch.menu.FlashMode.qio120.build.flash_freq=80m +waveshare_esp32_s3_relay_6ch.menu.FlashMode.dio=DIO 80MHz +waveshare_esp32_s3_relay_6ch.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_s3_relay_6ch.menu.FlashMode.dio.build.boot=dio +waveshare_esp32_s3_relay_6ch.menu.FlashMode.dio.build.boot_freq=80m +waveshare_esp32_s3_relay_6ch.menu.FlashMode.dio.build.flash_freq=80m +waveshare_esp32_s3_relay_6ch.menu.FlashMode.opi=OPI 80MHz +waveshare_esp32_s3_relay_6ch.menu.FlashMode.opi.build.flash_mode=dout +waveshare_esp32_s3_relay_6ch.menu.FlashMode.opi.build.boot=opi +waveshare_esp32_s3_relay_6ch.menu.FlashMode.opi.build.boot_freq=80m +waveshare_esp32_s3_relay_6ch.menu.FlashMode.opi.build.flash_freq=80m + +waveshare_esp32_s3_relay_6ch.menu.FlashSize.8M=8MB (64Mb) +waveshare_esp32_s3_relay_6ch.menu.FlashSize.8M.build.flash_size=8MB +waveshare_esp32_s3_relay_6ch.menu.FlashSize.8M.build.partitions=default_8MB +waveshare_esp32_s3_relay_6ch.menu.FlashSize.16M=16MB (128Mb) +waveshare_esp32_s3_relay_6ch.menu.FlashSize.16M.build.flash_size=16MB + +waveshare_esp32_s3_relay_6ch.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_relay_6ch.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_relay_6ch.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_relay_6ch.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_relay_6ch.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_relay_6ch.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_relay_6ch.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_relay_6ch.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_relay_6ch.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_relay_6ch.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_relay_6ch.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_relay_6ch.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_relay_6ch.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_relay_6ch.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_relay_6ch.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_relay_6ch.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_relay_6ch.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_relay_6ch.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_relay_6ch.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_relay_6ch.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_relay_6ch.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_relay_6ch.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_relay_6ch.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_relay_6ch.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_relay_6ch.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_relay_6ch.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_relay_6ch.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_relay_6ch.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_relay_6ch.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_relay_6ch.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.esp_sr_16=ESP SR 16M (3MB APP/7MB SPIFFS/2.9MB MODEL) +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.esp_sr_16.upload.maximum_size=3145728 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.esp_sr_16.upload.extra_flags=0xD10000 {build.path}/srmodels.bin +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_relay_6ch.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_relay_6ch.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_relay_6ch.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.none=None +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.error=Error +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.info=Info +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_relay_6ch.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_relay_6ch.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_relay_6ch.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_relay_6ch.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_relay_6ch.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_s3_relay_6ch.menu.ZigbeeMode.default=Disabled +waveshare_esp32_s3_relay_6ch.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_s3_relay_6ch.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_s3_relay_6ch.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_s3_relay_6ch.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_s3_relay_6ch.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port + +############################################################## diff --git a/variants/waveshare_esp32_s3_lcd_146/pins_arduino.h b/variants/waveshare_esp32_s3_lcd_146/pins_arduino.h new file mode 100644 index 00000000000..2539f207bd0 --- /dev/null +++ b/variants/waveshare_esp32_s3_lcd_146/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8258 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-1.46" +#define USB_SERIAL "" + +// I2C pins +static const uint8_t SCL = 10; +static const uint8_t SDA = 11; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_lcd_147/pins_arduino.h b/variants/waveshare_esp32_s3_lcd_147/pins_arduino.h new file mode 100644 index 00000000000..b79a970c1ef --- /dev/null +++ b/variants/waveshare_esp32_s3_lcd_147/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x828A + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-LCD-1.47" +#define USB_SERIAL "" + +#define PIN_RGB_LED 38 + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +static const uint8_t SS = 10; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 13; +static const uint8_t SCK = 12; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_lcd_185/pins_arduino.h b/variants/waveshare_esp32_s3_lcd_185/pins_arduino.h new file mode 100644 index 00000000000..f8542f014e7 --- /dev/null +++ b/variants/waveshare_esp32_s3_lcd_185/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8290 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-LCD-1.85" +#define USB_SERIAL "" + +// I2C pins +static const uint8_t SCL = 10; +static const uint8_t SDA = 11; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_relay_6ch/pins_arduino.h b/variants/waveshare_esp32_s3_relay_6ch/pins_arduino.h new file mode 100644 index 00000000000..f389f5e1358 --- /dev/null +++ b/variants/waveshare_esp32_s3_relay_6ch/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8273 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Relay-6CH" +#define USB_SERIAL "" + +#define PIN_RGB_LED 38 + +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SS = 10; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 13; +static const uint8_t SCK = 12; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_146/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_146/pins_arduino.h new file mode 100644 index 00000000000..1c14bfe6714 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_146/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8287 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-1.85-Box" +#define USB_SERIAL "" + +// I2C pins +static const uint8_t SCL = 10; +static const uint8_t SDA = 11; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_185_box/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_185_box/pins_arduino.h new file mode 100644 index 00000000000..438da04025a --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_185_box/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x825B + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-2.1" +#define USB_SERIAL "" + +// I2C pins +static const uint8_t SCL = 7; +static const uint8_t SDA = 15; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_21/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_21/pins_arduino.h new file mode 100644 index 00000000000..a6c76a7ff34 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_21/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x825E + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-2.8" +#define USB_SERIAL "" + +// I2C pins +static const uint8_t SCL = 10; +static const uint8_t SDA = 11; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_lcd_28/pins_arduino.h b/variants/waveshare_esp32_s3_touch_lcd_28/pins_arduino.h new file mode 100644 index 00000000000..a6c76a7ff34 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_lcd_28/pins_arduino.h @@ -0,0 +1,64 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x825E + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-LCD-2.8" +#define USB_SERIAL "" + +// I2C pins +static const uint8_t SCL = 10; +static const uint8_t SDA = 11; + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// Mapping based on the ESP32S3 data sheet - alternate for SPI2 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +#endif /* Pins_Arduino_h */ From 6e88445ba90e2eb8bdfb14f128b1d1773c0bdabb Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 23 Oct 2024 15:30:30 +0300 Subject: [PATCH 101/406] fix(i2s): Use separate variables when reading and writing (#10509) --- libraries/ESP_I2S/src/ESP_I2S.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libraries/ESP_I2S/src/ESP_I2S.cpp b/libraries/ESP_I2S/src/ESP_I2S.cpp index 395c7b587ed..f4bd92b52d5 100644 --- a/libraries/ESP_I2S/src/ESP_I2S.cpp +++ b/libraries/ESP_I2S/src/ESP_I2S.cpp @@ -806,17 +806,19 @@ bool I2SClass::configureRX(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slo size_t I2SClass::readBytes(char *buffer, size_t size) { size_t bytes_read = 0; + size_t bytes_to_read = 0; size_t total_size = 0; last_error = ESP_FAIL; if (rx_chan == NULL) { return total_size; } while (total_size < size) { - bytes_read = size - total_size; - if (rx_transform_buf != NULL && bytes_read > I2S_READ_CHUNK_SIZE) { - bytes_read = I2S_READ_CHUNK_SIZE; + bytes_read = 0; + bytes_to_read = size - total_size; + if (rx_transform_buf != NULL && bytes_to_read > I2S_READ_CHUNK_SIZE) { + bytes_to_read = I2S_READ_CHUNK_SIZE; } - I2S_ERROR_CHECK_RETURN(rx_fn(rx_chan, rx_transform_buf, (char *)(buffer + total_size), bytes_read, &bytes_read, _timeout), 0); + I2S_ERROR_CHECK_RETURN(rx_fn(rx_chan, rx_transform_buf, (char *)(buffer + total_size), bytes_to_read, &bytes_read, _timeout), 0); total_size += bytes_read; } return total_size; @@ -825,13 +827,15 @@ size_t I2SClass::readBytes(char *buffer, size_t size) { size_t I2SClass::write(const uint8_t *buffer, size_t size) { size_t written = 0; size_t bytes_sent = 0; + size_t bytes_to_send = 0; last_error = ESP_FAIL; if (tx_chan == NULL) { return written; } while (written < size) { - bytes_sent = size - written; - esp_err_t err = i2s_channel_write(tx_chan, (char *)(buffer + written), bytes_sent, &bytes_sent, _timeout); + bytes_sent = 0; + bytes_to_send = size - written; + esp_err_t err = i2s_channel_write(tx_chan, (char *)(buffer + written), bytes_to_send, &bytes_sent, _timeout); setWriteError(err); I2S_ERROR_CHECK_RETURN(err, written); written += bytes_sent; From cb83cda06a621b095e52029edbfa4049a9a84bb9 Mon Sep 17 00:00:00 2001 From: Thomas Weller Date: Wed, 23 Oct 2024 19:39:12 +0200 Subject: [PATCH 102/406] Fix comments for AD types in advertising (#10512) --- libraries/BLE/src/BLEAdvertising.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/BLE/src/BLEAdvertising.cpp b/libraries/BLE/src/BLEAdvertising.cpp index 1f2e6cd2887..2d71c4d7478 100644 --- a/libraries/BLE/src/BLEAdvertising.cpp +++ b/libraries/BLE/src/BLEAdvertising.cpp @@ -352,7 +352,7 @@ void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { switch (uuid.bitSize()) { case 16: { - // [Len] [0x02] [LL] [HH] + // [Len] [0x03] [LL] [HH] cdata[0] = 3; cdata[1] = ESP_BLE_AD_TYPE_16SRV_CMPL; // 0x03 addData(String(cdata, 2) + String((char *)&uuid.getNative()->uuid.uuid16, 2)); @@ -361,7 +361,7 @@ void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { case 32: { - // [Len] [0x04] [LL] [LL] [HH] [HH] + // [Len] [0x05] [LL] [LL] [HH] [HH] cdata[0] = 5; cdata[1] = ESP_BLE_AD_TYPE_32SRV_CMPL; // 0x05 addData(String(cdata, 2) + String((char *)&uuid.getNative()->uuid.uuid32, 4)); @@ -370,7 +370,7 @@ void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { case 128: { - // [Len] [0x04] [0] [1] ... [15] + // [Len] [0x07] [0] [1] ... [15] cdata[0] = 17; cdata[1] = ESP_BLE_AD_TYPE_128SRV_CMPL; // 0x07 addData(String(cdata, 2) + String((char *)uuid.getNative()->uuid.uuid128, 16)); @@ -453,7 +453,7 @@ void BLEAdvertisementData::setPartialServices(BLEUUID uuid) { case 128: { - // [Len] [0x04] [0] [1] ... [15] + // [Len] [0x06] [0] [1] ... [15] cdata[0] = 17; cdata[1] = ESP_BLE_AD_TYPE_128SRV_PART; // 0x06 addData(String(cdata, 2) + String((char *)&uuid.getNative()->uuid.uuid128, 16)); From 6dfd95898387bf10eb6348a22c2499073efb9f16 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 24 Oct 2024 00:46:01 +0300 Subject: [PATCH 103/406] fix(eth): Set default clock in pin value to zero (#10513) When Arduino is used as component, `CONFIG_ETH_RMII_CLK_IN_GPIO` might not be defined, so we set it to const `0` to clear the issue. --- libraries/Ethernet/src/ETH.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index e04174fd490..e3f2197221c 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -210,7 +210,7 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i #if CONFIG_IDF_TARGET_ESP32 #undef DEFAULT_RMII_CLK_GPIO -#define DEFAULT_RMII_CLK_GPIO (emac_rmii_clock_gpio_t)(CONFIG_ETH_RMII_CLK_IN_GPIO) +#define DEFAULT_RMII_CLK_GPIO (emac_rmii_clock_gpio_t)(0) #endif eth_esp32_emac_config_t mac_config = ETH_EMAC_DEFAULT_CONFIG(); From 330beb40a501f2006abfbc9241fd81dc306d676b Mon Sep 17 00:00:00 2001 From: zinkett <96108358+zinkett@users.noreply.github.com> Date: Thu, 24 Oct 2024 13:31:54 +0200 Subject: [PATCH 104/406] Update lib - User can choose if calc MD5 from encrypted or decrypted file (#10510) * User can choose if calc MD5 from decrypted file At the present moment, if user want use OTA, the function calculate MD5 of the decrypted file, but if file is encrypted from source, could be more useful to know the MD5 of the encrypted file. * md5 * Update Updater.cpp * Update libraries/Update/src/Update.h Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * Update libraries/Update/src/Update.h Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * Update libraries/Update/src/Updater.cpp Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * Update libraries/Update/src/Updater.cpp Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- libraries/Update/src/Update.h | 4 +++- libraries/Update/src/Updater.cpp | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libraries/Update/src/Update.h b/libraries/Update/src/Update.h index 7ae5e980751..5832846fd28 100644 --- a/libraries/Update/src/Update.h +++ b/libraries/Update/src/Update.h @@ -137,8 +137,9 @@ class UpdateClass { /* sets the expected MD5 for the firmware (hexString) + If calc_post_decryption is true, the update library will calculate the MD5 after the decryption, if false the calculation occurs before the decryption */ - bool setMD5(const char *expected_md5); + bool setMD5(const char *expected_md5, bool calc_post_decryption = true); /* returns the MD5 String of the successfully ended firmware @@ -257,6 +258,7 @@ class UpdateClass { const esp_partition_t *_partition; String _target_md5; + bool _target_md5_decrypted = true; MD5Builder _md5; int _ledPin; diff --git a/libraries/Update/src/Updater.cpp b/libraries/Update/src/Updater.cpp index 78f93602cde..e92f84d4599 100644 --- a/libraries/Update/src/Updater.cpp +++ b/libraries/Update/src/Updater.cpp @@ -348,6 +348,11 @@ bool UpdateClass::_writeBuffer() { log_d("Decrypting OTA Image"); } } + + if (!_target_md5_decrypted) { + _md5.add(_buffer, _bufferLen); + } + //check if data in buffer needs decrypting if (_cryptMode & U_AES_IMAGE_DECRYPTING_BIT) { if (!_decryptBuffer()) { @@ -404,7 +409,9 @@ bool UpdateClass::_writeBuffer() { if (!_progress && _command == U_FLASH) { _buffer[0] = ESP_IMAGE_HEADER_MAGIC; } - _md5.add(_buffer, _bufferLen); + if (_target_md5_decrypted) { + _md5.add(_buffer, _bufferLen); + } _progress += _bufferLen; _bufferLen = 0; if (_progress_callback) { @@ -446,12 +453,13 @@ bool UpdateClass::_verifyEnd() { return false; } -bool UpdateClass::setMD5(const char *expected_md5) { +bool UpdateClass::setMD5(const char *expected_md5, bool calc_post_decryption) { if (strlen(expected_md5) != 32) { return false; } _target_md5 = expected_md5; _target_md5.toLowerCase(); + _target_md5_decrypted = calc_post_decryption; return true; } From 07c510e3adc0dfe4a284d0f47d6ecd07286c712f Mon Sep 17 00:00:00 2001 From: vortigont Date: Thu, 24 Oct 2024 21:15:13 +0900 Subject: [PATCH 105/406] fix (NetworkEvents lib) remove checks for duplicated event handlers (#10376) * lib Network: add cpp syntax to structs * [Network] deprecate NetworkEvents::removeEvent() for std::function callbacks removing event callback via std::function pointer does not work as expected for lambdas (issue #10365) here mark NetworkEvents::removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX) as deprecated in favor of removing by callback's id for NetworkEvents::onEvent remove checking for dublicate event handler, this does not work for lambdas too remove NetworkEvents::find methods as unnecessary move cbEventList container inside the class declare NetworkEventCbList_t as a cpp struct with constructor, allows using std::vector.emplace() when adding new items to container optimize NetworkEvents::remove() calls to use erase-remove idiom for std::vector * [Network] hide event task under private member of NetworkEvents class prevent checkForEvent loop to be callable from outside the task's thread * refactor(NetworkEvents) code polishing and comments - rename NetworkEvents::cbEventList as private member NetworkEvents_cbEventList - NetworkEvents::getStatusBits() add const qualifier - turn statics into constexpr - add indexes to enum::arduino_event_id_t to make events indexing consistent for SOCs with/without WiFi also leave some index gaps to minimize renumbering on adding new events - add doxygen help to NetworkEvents:: methods - declare NetworkEvents::eventName() as static, that could be used without creating class scope - potential mem leak in postEvent * refactor(NetworkEvents) add (optional) mutex lock for container operations provide thread safety for dual core SoCs since std::mutex brings additional componetns of libstdc++ lib it impacts resulting image size significantly (around 50k) Might be enabled on-demand if thread-safety is required * ci(pre-commit): Apply automatic fixes * fix(spelling): Fix spelling mistakes --------- Co-authored-by: Rodrigo Garcia Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> --- libraries/Network/src/NetworkEvents.cpp | 325 ++++++++++-------------- libraries/Network/src/NetworkEvents.h | 180 +++++++++++-- 2 files changed, 289 insertions(+), 216 deletions(-) diff --git a/libraries/Network/src/NetworkEvents.cpp b/libraries/Network/src/NetworkEvents.cpp index bb02282e9b3..5a7e7c49afa 100644 --- a/libraries/Network/src/NetworkEvents.cpp +++ b/libraries/Network/src/NetworkEvents.cpp @@ -8,28 +8,6 @@ #include "esp_task.h" #include "esp32-hal.h" -typedef struct NetworkEventCbList { - static network_event_handle_t current_id; - network_event_handle_t id; - NetworkEventCb cb; - NetworkEventFuncCb fcb; - NetworkEventSysCb scb; - arduino_event_id_t event; - - NetworkEventCbList() : id(current_id++), cb(NULL), fcb(NULL), scb(NULL), event(ARDUINO_EVENT_NONE) {} -} NetworkEventCbList_t; -network_event_handle_t NetworkEventCbList::current_id = 1; - -// arduino dont like std::vectors move static here -static std::vector cbEventList; - -static void _network_event_task(void *arg) { - for (;;) { - ((NetworkEvents *)arg)->checkForEvent(); - } - vTaskDelete(NULL); -} - NetworkEvents::NetworkEvents() : _arduino_event_group(NULL), _arduino_event_queue(NULL), _arduino_event_task_handle(NULL) {} NetworkEvents::~NetworkEvents() { @@ -43,8 +21,9 @@ NetworkEvents::~NetworkEvents() { } if (_arduino_event_queue != NULL) { arduino_event_t *event = NULL; + // consume queue while (xQueueReceive(_arduino_event_queue, &event, 0) == pdTRUE) { - free(event); + delete event; } vQueueDelete(_arduino_event_queue); _arduino_event_queue = NULL; @@ -78,7 +57,14 @@ bool NetworkEvents::initNetworkEvents() { } if (!_arduino_event_task_handle) { - xTaskCreateUniversal(_network_event_task, "arduino_events", 4096, this, ESP_TASKD_EVENT_PRIO - 1, &_arduino_event_task_handle, ARDUINO_EVENT_RUNNING_CORE); + xTaskCreateUniversal( + [](void *self) { + static_cast(self)->_checkForEvent(); + }, + "arduino_events", // label + 4096, // event task's stack size + this, ESP_TASKD_EVENT_PRIO - 1, &_arduino_event_task_handle, ARDUINO_EVENT_RUNNING_CORE + ); if (!_arduino_event_task_handle) { log_e("Network Event Task Start Failed!"); return false; @@ -88,66 +74,76 @@ bool NetworkEvents::initNetworkEvents() { return true; } -bool NetworkEvents::postEvent(arduino_event_t *data) { +bool NetworkEvents::postEvent(const arduino_event_t *data) { if (data == NULL || _arduino_event_queue == NULL) { return false; } - arduino_event_t *event = (arduino_event_t *)malloc(sizeof(arduino_event_t)); + arduino_event_t *event = new arduino_event_t(); if (event == NULL) { log_e("Arduino Event Malloc Failed!"); return false; } + memcpy(event, data, sizeof(arduino_event_t)); if (xQueueSend(_arduino_event_queue, &event, portMAX_DELAY) != pdPASS) { log_e("Arduino Event Send Failed!"); + delete event; // release mem on error return false; } return true; } -void NetworkEvents::checkForEvent() { - arduino_event_t *event = NULL; +void NetworkEvents::_checkForEvent() { + // this task can't run without the queue if (_arduino_event_queue == NULL) { + _arduino_event_task_handle = NULL; + vTaskDelete(NULL); return; } - if (xQueueReceive(_arduino_event_queue, &event, portMAX_DELAY) != pdTRUE) { - return; - } - if (event == NULL) { - return; - } - log_v("Network Event: %d - %s", event->event_id, eventName(event->event_id)); - for (uint32_t i = 0; i < cbEventList.size(); i++) { - NetworkEventCbList_t entry = cbEventList[i]; - if (entry.cb || entry.fcb || entry.scb) { - if (entry.event == (arduino_event_id_t)event->event_id || entry.event == ARDUINO_EVENT_MAX) { - if (entry.cb) { - entry.cb((arduino_event_id_t)event->event_id); - } else if (entry.fcb) { - entry.fcb((arduino_event_id_t)event->event_id, (arduino_event_info_t)event->event_info); - } else { - entry.scb(event); + + for (;;) { + arduino_event_t *event = NULL; + // wait for an event on a queue + if (xQueueReceive(_arduino_event_queue, &event, portMAX_DELAY) != pdTRUE) { + continue; + } + if (event == NULL) { + continue; + } + log_v("Network Event: %d - %s", event->event_id, eventName(event->event_id)); + +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::unique_lock lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + + // iterate over registered callbacks + for (auto &i : _cbEventList) { + if (i.cb || i.fcb || i.scb) { + if (i.event == (arduino_event_id_t)event->event_id || i.event == ARDUINO_EVENT_MAX) { + if (i.cb) { + i.cb((arduino_event_id_t)event->event_id); + continue; + } + + if (i.fcb) { + i.fcb((arduino_event_id_t)event->event_id, (arduino_event_info_t)event->event_info); + continue; + } + + i.scb(event); } } } - } - free(event); -} -uint32_t NetworkEvents::findEvent(NetworkEventCb cbEvent, arduino_event_id_t event) { - uint32_t i; +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + lock.unlock(); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - if (!cbEvent) { - return cbEventList.size(); + // release the event object's memory + delete event; } - for (i = 0; i < cbEventList.size(); i++) { - NetworkEventCbList_t entry = cbEventList[i]; - if (entry.cb == cbEvent && entry.event == event) { - break; - } - } - return i; + vTaskDelete(NULL); } template static size_t getStdFunctionAddress(std::function f) { @@ -159,55 +155,17 @@ template static size_t getStdFunctionAddress(std::fun return (size_t)fnPointer; } -uint32_t NetworkEvents::findEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) { - uint32_t i; - - if (!cbEvent) { - return cbEventList.size(); - } - - for (i = 0; i < cbEventList.size(); i++) { - NetworkEventCbList_t entry = cbEventList[i]; - if (getStdFunctionAddress(entry.fcb) == getStdFunctionAddress(cbEvent) && entry.event == event) { - break; - } - } - return i; -} - -uint32_t NetworkEvents::findEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) { - uint32_t i; - - if (!cbEvent) { - return cbEventList.size(); - } - - for (i = 0; i < cbEventList.size(); i++) { - NetworkEventCbList_t entry = cbEventList[i]; - if (entry.scb == cbEvent && entry.event == event) { - break; - } - } - return i; -} - network_event_handle_t NetworkEvents::onEvent(NetworkEventCb cbEvent, arduino_event_id_t event) { if (!cbEvent) { return 0; } - if (findEvent(cbEvent, event) < cbEventList.size()) { - log_w("Attempt to add duplicate event handler!"); - return 0; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - NetworkEventCbList_t newEventHandler; - newEventHandler.cb = cbEvent; - newEventHandler.fcb = NULL; - newEventHandler.scb = NULL; - newEventHandler.event = event; - cbEventList.push_back(newEventHandler); - return newEventHandler.id; + _cbEventList.emplace_back(++_current_id, cbEvent, nullptr, nullptr, event); + return _cbEventList.back().id; } network_event_handle_t NetworkEvents::onEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) { @@ -215,18 +173,12 @@ network_event_handle_t NetworkEvents::onEvent(NetworkEventFuncCb cbEvent, arduin return 0; } - if (findEvent(cbEvent, event) < cbEventList.size()) { - log_w("Attempt to add duplicate event handler!"); - return 0; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - NetworkEventCbList_t newEventHandler; - newEventHandler.cb = NULL; - newEventHandler.fcb = cbEvent; - newEventHandler.scb = NULL; - newEventHandler.event = event; - cbEventList.push_back(newEventHandler); - return newEventHandler.id; + _cbEventList.emplace_back(++_current_id, nullptr, cbEvent, nullptr, event); + return _cbEventList.back().id; } network_event_handle_t NetworkEvents::onEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) { @@ -234,18 +186,12 @@ network_event_handle_t NetworkEvents::onEvent(NetworkEventSysCb cbEvent, arduino return 0; } - if (findEvent(cbEvent, event) < cbEventList.size()) { - log_w("Attempt to add duplicate event handler!"); - return 0; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - NetworkEventCbList_t newEventHandler; - newEventHandler.cb = NULL; - newEventHandler.fcb = NULL; - newEventHandler.scb = cbEvent; - newEventHandler.event = event; - cbEventList.push_back(newEventHandler); - return newEventHandler.id; + _cbEventList.emplace_back(++_current_id, nullptr, nullptr, cbEvent, event); + return _cbEventList.back().id; } network_event_handle_t NetworkEvents::onSysEvent(NetworkEventCb cbEvent, arduino_event_id_t event) { @@ -253,18 +199,12 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventCb cbEvent, arduino return 0; } - if (findEvent(cbEvent, event) < cbEventList.size()) { - log_w("Attempt to add duplicate event handler!"); - return 0; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - NetworkEventCbList_t newEventHandler; - newEventHandler.cb = cbEvent; - newEventHandler.fcb = NULL; - newEventHandler.scb = NULL; - newEventHandler.event = event; - cbEventList.insert(cbEventList.begin(), newEventHandler); - return newEventHandler.id; + _cbEventList.emplace(_cbEventList.begin(), ++_current_id, cbEvent, nullptr, nullptr, event); + return _cbEventList.front().id; } network_event_handle_t NetworkEvents::onSysEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) { @@ -272,18 +212,12 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventFuncCb cbEvent, ard return 0; } - if (findEvent(cbEvent, event) < cbEventList.size()) { - log_w("Attempt to add duplicate event handler!"); - return 0; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - NetworkEventCbList_t newEventHandler; - newEventHandler.cb = NULL; - newEventHandler.fcb = cbEvent; - newEventHandler.scb = NULL; - newEventHandler.event = event; - cbEventList.insert(cbEventList.begin(), newEventHandler); - return newEventHandler.id; + _cbEventList.emplace(_cbEventList.begin(), ++_current_id, nullptr, cbEvent, nullptr, event); + return _cbEventList.front().id; } network_event_handle_t NetworkEvents::onSysEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) { @@ -291,77 +225,88 @@ network_event_handle_t NetworkEvents::onSysEvent(NetworkEventSysCb cbEvent, ardu return 0; } - if (findEvent(cbEvent, event) < cbEventList.size()) { - log_w("Attempt to add duplicate event handler!"); - return 0; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - NetworkEventCbList_t newEventHandler; - newEventHandler.cb = NULL; - newEventHandler.fcb = NULL; - newEventHandler.scb = cbEvent; - newEventHandler.event = event; - cbEventList.insert(cbEventList.begin(), newEventHandler); - return newEventHandler.id; + _cbEventList.emplace(_cbEventList.begin(), ++_current_id, nullptr, nullptr, cbEvent, event); + return _cbEventList.front().id; } void NetworkEvents::removeEvent(NetworkEventCb cbEvent, arduino_event_id_t event) { - uint32_t i; - if (!cbEvent) { return; } - i = findEvent(cbEvent, event); - if (i >= cbEventList.size()) { - log_w("Event handler not found!"); - return; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - cbEventList.erase(cbEventList.begin() + i); + _cbEventList.erase( + std::remove_if( + _cbEventList.begin(), _cbEventList.end(), + [cbEvent, event](const NetworkEventCbList_t &e) { + return e.cb == cbEvent && e.event == event; + } + ), + _cbEventList.end() + ); } void NetworkEvents::removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event) { - uint32_t i; - if (!cbEvent) { return; } - i = findEvent(cbEvent, event); - if (i >= cbEventList.size()) { - log_w("Event handler not found!"); - return; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - cbEventList.erase(cbEventList.begin() + i); + _cbEventList.erase( + std::remove_if( + _cbEventList.begin(), _cbEventList.end(), + [cbEvent, event](const NetworkEventCbList_t &e) { + return getStdFunctionAddress(e.fcb) == getStdFunctionAddress(cbEvent) && e.event == event; + } + ), + _cbEventList.end() + ); } void NetworkEvents::removeEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event) { - uint32_t i; - if (!cbEvent) { return; } - i = findEvent(cbEvent, event); - if (i >= cbEventList.size()) { - log_w("Event handler not found!"); - return; - } +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 - cbEventList.erase(cbEventList.begin() + i); + _cbEventList.erase( + std::remove_if( + _cbEventList.begin(), _cbEventList.end(), + [cbEvent, event](const NetworkEventCbList_t &e) { + return e.scb == cbEvent && e.event == event; + } + ), + _cbEventList.end() + ); } void NetworkEvents::removeEvent(network_event_handle_t id) { - for (uint32_t i = 0; i < cbEventList.size(); i++) { - NetworkEventCbList_t entry = cbEventList[i]; - if (entry.id == id) { - cbEventList.erase(cbEventList.begin() + i); - return; - } - } - log_w("Event handler not found!"); +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + std::lock_guard lock(_mtx); +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + + _cbEventList.erase( + std::remove_if( + _cbEventList.begin(), _cbEventList.end(), + [id](const NetworkEventCbList_t &e) { + return e.id == id; + } + ), + _cbEventList.end() + ); } int NetworkEvents::setStatusBits(int bits) { @@ -380,7 +325,7 @@ int NetworkEvents::clearStatusBits(int bits) { return xEventGroupClearBits(_arduino_event_group, bits); } -int NetworkEvents::getStatusBits() { +int NetworkEvents::getStatusBits() const { if (!_arduino_event_group) { return _initial_bits; } diff --git a/libraries/Network/src/NetworkEvents.h b/libraries/Network/src/NetworkEvents.h index ac324d19841..e134d6816a2 100644 --- a/libraries/Network/src/NetworkEvents.h +++ b/libraries/Network/src/NetworkEvents.h @@ -16,6 +16,9 @@ #include "freertos/queue.h" #include "freertos/semphr.h" #include "freertos/event_groups.h" +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 +#include +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 #if SOC_WIFI_SUPPORTED #include "esp_wifi_types.h" @@ -24,8 +27,8 @@ #endif #if SOC_WIFI_SUPPORTED -static const int WIFI_SCANNING_BIT = BIT0; -static const int WIFI_SCAN_DONE_BIT = BIT1; +constexpr int WIFI_SCANNING_BIT = BIT0; +constexpr int WIFI_SCAN_DONE_BIT = BIT1; #endif #define NET_HAS_IP6_GLOBAL_BIT 0 @@ -33,7 +36,7 @@ static const int WIFI_SCAN_DONE_BIT = BIT1; ESP_EVENT_DECLARE_BASE(ARDUINO_EVENTS); typedef enum { - ARDUINO_EVENT_NONE, + ARDUINO_EVENT_NONE = 0, ARDUINO_EVENT_ETH_START, ARDUINO_EVENT_ETH_STOP, ARDUINO_EVENT_ETH_CONNECTED, @@ -42,10 +45,11 @@ typedef enum { ARDUINO_EVENT_ETH_LOST_IP, ARDUINO_EVENT_ETH_GOT_IP6, #if SOC_WIFI_SUPPORTED - ARDUINO_EVENT_WIFI_OFF, + ARDUINO_EVENT_WIFI_OFF = 100, ARDUINO_EVENT_WIFI_READY, ARDUINO_EVENT_WIFI_SCAN_DONE, - ARDUINO_EVENT_WIFI_STA_START, + ARDUINO_EVENT_WIFI_FTM_REPORT, + ARDUINO_EVENT_WIFI_STA_START = 110, ARDUINO_EVENT_WIFI_STA_STOP, ARDUINO_EVENT_WIFI_STA_CONNECTED, ARDUINO_EVENT_WIFI_STA_DISCONNECTED, @@ -53,24 +57,23 @@ typedef enum { ARDUINO_EVENT_WIFI_STA_GOT_IP, ARDUINO_EVENT_WIFI_STA_GOT_IP6, ARDUINO_EVENT_WIFI_STA_LOST_IP, - ARDUINO_EVENT_WIFI_AP_START, + ARDUINO_EVENT_WIFI_AP_START = 130, ARDUINO_EVENT_WIFI_AP_STOP, ARDUINO_EVENT_WIFI_AP_STACONNECTED, ARDUINO_EVENT_WIFI_AP_STADISCONNECTED, ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED, ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED, ARDUINO_EVENT_WIFI_AP_GOT_IP6, - ARDUINO_EVENT_WIFI_FTM_REPORT, - ARDUINO_EVENT_WPS_ER_SUCCESS, + ARDUINO_EVENT_WPS_ER_SUCCESS = 140, ARDUINO_EVENT_WPS_ER_FAILED, ARDUINO_EVENT_WPS_ER_TIMEOUT, ARDUINO_EVENT_WPS_ER_PIN, ARDUINO_EVENT_WPS_ER_PBC_OVERLAP, - ARDUINO_EVENT_SC_SCAN_DONE, + ARDUINO_EVENT_SC_SCAN_DONE = 150, ARDUINO_EVENT_SC_FOUND_CHANNEL, ARDUINO_EVENT_SC_GOT_SSID_PSWD, ARDUINO_EVENT_SC_SEND_ACK_DONE, - ARDUINO_EVENT_PROV_INIT, + ARDUINO_EVENT_PROV_INIT = 160, ARDUINO_EVENT_PROV_DEINIT, ARDUINO_EVENT_PROV_START, ARDUINO_EVENT_PROV_END, @@ -78,7 +81,7 @@ typedef enum { ARDUINO_EVENT_PROV_CRED_FAIL, ARDUINO_EVENT_PROV_CRED_SUCCESS, #endif - ARDUINO_EVENT_PPP_START, + ARDUINO_EVENT_PPP_START = 200, ARDUINO_EVENT_PPP_STOP, ARDUINO_EVENT_PPP_CONNECTED, ARDUINO_EVENT_PPP_DISCONNECTED, @@ -110,36 +113,123 @@ typedef union { #endif } arduino_event_info_t; -typedef struct { +/** + * @brief struct combines arduino event id and event's data object + * + */ +struct arduino_event_t { arduino_event_id_t event_id; arduino_event_info_t event_info; -} arduino_event_t; - -typedef void (*NetworkEventCb)(arduino_event_id_t event); -typedef std::function NetworkEventFuncCb; -typedef void (*NetworkEventSysCb)(arduino_event_t *event); +}; -typedef size_t network_event_handle_t; +// type aliases +using NetworkEventCb = void (*)(arduino_event_id_t event); +using NetworkEventFuncCb = std::function; +using NetworkEventSysCb = void (*)(arduino_event_t *event); +using network_event_handle_t = size_t; +/** + * @brief Class that provides network events callback handling + * it registers user callback functions for event handling, + * maintains the queue of events and propagates the event among subscribed callbacks + * callback are called in the context of a dedicated task consuming the queue + * + */ class NetworkEvents { public: NetworkEvents(); ~NetworkEvents(); + /** + * @brief register callback function to be executed on arduino event(s) + * @note if same handler is registered twice or more than same handler would be called twice or more times + * + * @param cbEvent static callback function + * @param event event to process, any event by default + * @return network_event_handle_t + */ network_event_handle_t onEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); + + /** + * @brief register functional callback to be executed on arduino event(s) + * also used for lambda callbacks + * @note if same handler is registered twice or more than same handler would be called twice or more times + * + * @param cbEvent static callback function + * @param event event to process, any event by default + * @return network_event_handle_t + */ network_event_handle_t onEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); + + /** + * @brief register static system callback to be executed on arduino event(s) + * callback function would be supplied with a pointer to arduino_event_t structure as an argument + * + * @note if same handler is registered twice or more than same handler would be called twice or more times + * + * @param cbEvent static callback function + * @param event event to process, any event by default + * @return network_event_handle_t + */ network_event_handle_t onEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); + + /** + * @brief unregister static function callback + * @note a better way to unregister callbacks is to save/unregister via network_event_handle_t + * + * @param cbEvent static callback function + * @param event event to process, any event by default + */ void removeEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); - void removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); + + /** + * @brief unregister functional callback + * @note a better way to unregister callbacks is to save/unregister via network_event_handle_t + * @note this does not work for lambda's! Do unregister via network_event_handle_t + * + * @param cbEvent functional callback + * @param event event to process, any event by default + */ + void removeEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX) + __attribute__((deprecated("removing functional callbacks via pointer is deprecated, use removeEvent(network_event_handle_t) instead"))); + + /** + * @brief unregister static system function callback + * @note a better way to unregister callbacks is to save/unregister via network_event_handle_t + * + * @param cbEvent static callback function + * @param event event to process, any event by default + */ void removeEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); + + /** + * @brief unregister event callback via handler + * + * @param cbEvent static callback function + * @param event event to process, any event by default + */ void removeEvent(network_event_handle_t event_handle); - const char *eventName(arduino_event_id_t id); + /** + * @brief get a human-readable name of an event by it's id + * + * @param id event id code + * @return const char* event name string + */ + static const char *eventName(arduino_event_id_t id); - void checkForEvent(); - bool postEvent(arduino_event_t *event); + /** + * @brief post an event to the queue + * and propagade and event to subscribed handlers + * @note posting an event will trigger context switch from a lower priority task + * + * @param event a pointer to arduino_event_t struct + * @return true if event was queued susccessfuly + * @return false on memrory allocation error or queue is full + */ + bool postEvent(const arduino_event_t *event); - int getStatusBits(); + int getStatusBits() const; int waitStatusBits(int bits, uint32_t timeout_ms); int setStatusBits(int bits); int clearStatusBits(int bits); @@ -155,15 +245,53 @@ class NetworkEvents { protected: bool initNetworkEvents(); - uint32_t findEvent(NetworkEventCb cbEvent, arduino_event_id_t event); - uint32_t findEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event); - uint32_t findEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event); + // same as onEvent() but places newly added handler at the beginning of registered events list network_event_handle_t onSysEvent(NetworkEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); + // same as onEvent() but places newly added handler at the beginning of registered events list network_event_handle_t onSysEvent(NetworkEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); + // same as onEvent() but places newly added handler at the beginning of registered events list network_event_handle_t onSysEvent(NetworkEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); private: + /** + * @brief an object holds callback's definitions: + * - callback id + * - callback function pointers + * - binded event id + * + */ + struct NetworkEventCbList_t { + network_event_handle_t id; + NetworkEventCb cb; + NetworkEventFuncCb fcb; + NetworkEventSysCb scb; + arduino_event_id_t event; + + explicit NetworkEventCbList_t( + network_event_handle_t id, NetworkEventCb cb = nullptr, NetworkEventFuncCb fcb = nullptr, NetworkEventSysCb scb = nullptr, + arduino_event_id_t event = ARDUINO_EVENT_MAX + ) + : id(id), cb(cb), fcb(fcb), scb(scb), event(event) {} + }; + + // define initial id's value + network_event_handle_t _current_id{0}; + EventGroupHandle_t _arduino_event_group; QueueHandle_t _arduino_event_queue; TaskHandle_t _arduino_event_task_handle; + + // registered events callbacks container + std::vector _cbEventList; + +#if defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + // container access mutex + std::mutex _mtx; +#endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 + + /** + * @brief task function that picks events from an event queue and calls registered callbacks + * + */ + void _checkForEvent(); }; From a3ee37669eaecbff6ef7180c675bf83cd94c4dc6 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:56:45 -0300 Subject: [PATCH 106/406] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ee43fa0537..5b1b1865efa 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Here are the ESP32 series supported by the Arduino-ESP32 project: | ESP32-S3 | Yes | Yes | [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) | | ESP32-C6 | Yes | Yes | [ESP32-C6](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) | | ESP32-H2 | Yes | Yes | [ESP32-H2](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) | -| ESP32-P4 | No | No | [ESP32-P4](https://www.espressif.com/sites/default/files/documentation/esp32-p4_datasheet_en.pdf) | +| ESP32-P4 | No | Yes | [ESP32-P4](https://www.espressif.com/sites/default/files/documentation/esp32-p4_datasheet_en.pdf) | > [!NOTE] > ESP32-C2 is also supported by Arduino-ESP32 but requires rebuilding the static libraries. This is not trivial and requires a good understanding of the ESP-IDF From 9ac705e5f2889a9cb425e8d24bb90ba4b1e092a2 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Fri, 25 Oct 2024 14:53:35 +0300 Subject: [PATCH 107/406] IDF release/v5.3 a0f798cf (#10522) --- package/package_esp32_index.template.json | 128 +++++++++++----------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index ad941e841f6..aafaa211eba 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -42,7 +42,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-59550599" + "version": "idf-release_v5.3-a0f798cf" }, { "packager": "esp32", @@ -67,7 +67,7 @@ { "packager": "esp32", "name": "openocd-esp32", - "version": "v0.12.0-esp32-20240821" + "version": "v0.12.0-esp32-20241016" }, { "packager": "esp32", @@ -95,63 +95,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.3-59550599", + "version": "idf-release_v5.3-a0f798cf", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", - "size": "343730097" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "checksum": "SHA-256:cc0c44739a2ae9b4d17b0026907132592a3888fdf3bb910c2ad730931fc6c9dc", + "size": "344062217" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", - "size": "343730097" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "checksum": "SHA-256:cc0c44739a2ae9b4d17b0026907132592a3888fdf3bb910c2ad730931fc6c9dc", + "size": "344062217" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", - "size": "343730097" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "checksum": "SHA-256:cc0c44739a2ae9b4d17b0026907132592a3888fdf3bb910c2ad730931fc6c9dc", + "size": "344062217" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", - "size": "343730097" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "checksum": "SHA-256:cc0c44739a2ae9b4d17b0026907132592a3888fdf3bb910c2ad730931fc6c9dc", + "size": "344062217" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", - "size": "343730097" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "checksum": "SHA-256:cc0c44739a2ae9b4d17b0026907132592a3888fdf3bb910c2ad730931fc6c9dc", + "size": "344062217" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", - "size": "343730097" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "checksum": "SHA-256:cc0c44739a2ae9b4d17b0026907132592a3888fdf3bb910c2ad730931fc6c9dc", + "size": "344062217" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", - "size": "343730097" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "checksum": "SHA-256:cc0c44739a2ae9b4d17b0026907132592a3888fdf3bb910c2ad730931fc6c9dc", + "size": "344062217" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-59550599.zip", - "checksum": "SHA-256:d2f18131dc7220c2d89ece7f8594fa3866523f8183612af37112ed0177f41af7", - "size": "343730097" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip", + "checksum": "SHA-256:cc0c44739a2ae9b4d17b0026907132592a3888fdf3bb910c2ad730931fc6c9dc", + "size": "344062217" } ] }, @@ -405,56 +405,56 @@ }, { "name": "openocd-esp32", - "version": "v0.12.0-esp32-20240821", + "version": "v0.12.0-esp32-20241016", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-amd64-0.12.0-esp32-20240821.tar.gz", - "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20240821.tar.gz", - "checksum": "SHA-256:f8c68541fa38307bc0c0763b7e1e3fe4e943d5d45da07d817a73b492e103b652", - "size": "2373094" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-amd64-0.12.0-esp32-20241016.tar.gz", + "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20241016.tar.gz", + "checksum": "SHA-256:e82b0f036dc99244bead5f09a86e91bb2365cbcd1122ac68261e5647942485df", + "size": "2398717" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-arm64-0.12.0-esp32-20240821.tar.gz", - "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20240821.tar.gz", - "checksum": "SHA-256:4d6e263d84e447354dc685848557d6c284dda7fe007ee451f729a7edfa7baad7", - "size": "2251272" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-arm64-0.12.0-esp32-20241016.tar.gz", + "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20241016.tar.gz", + "checksum": "SHA-256:8f8daf5bd22ec5d2fa9257b0862ec33da18ee677e023fb9a9eb17f74ce208c76", + "size": "2271584" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-armel-0.12.0-esp32-20240821.tar.gz", - "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20240821.tar.gz", - "checksum": "SHA-256:9d45679f2c4cf450d5e2350047cf57bb76dde2487d30cebce0a72c9173b5c45b", - "size": "2390074" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-armel-0.12.0-esp32-20241016.tar.gz", + "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20241016.tar.gz", + "checksum": "SHA-256:bc9c020ecf20e2000f76cffa44305fd5bc44d2e688ea78cce423399d33f19767", + "size": "2414206" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-macos-0.12.0-esp32-20240821.tar.gz", - "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20240821.tar.gz", - "checksum": "SHA-256:565c8fabc5f19a6e7a0864a294d74b307eec30b9291d16d3fc90e273f0330cb4", - "size": "2485320" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-macos-0.12.0-esp32-20241016.tar.gz", + "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20241016.tar.gz", + "checksum": "SHA-256:02a2dffe801a2d005fa9e614d80ff8173395b2cb0b5d3118d0229d094a9946a7", + "size": "2508089" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-macos-arm64-0.12.0-esp32-20240821.tar.gz", - "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20240821.tar.gz", - "checksum": "SHA-256:68c5c7cf3d15b9810939a5edabc6ff2c9f4fc32262de91fc292a180bc5cc0637", - "size": "2530336" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-macos-arm64-0.12.0-esp32-20241016.tar.gz", + "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20241016.tar.gz", + "checksum": "SHA-256:c382f9e884d6565cb6089bff5f200f4810994667d885f062c3d3c5625a0fa9d6", + "size": "2552569" }, { "host": "i686-mingw32", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-win32-0.12.0-esp32-20240821.zip", - "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20240821.zip", - "checksum": "SHA-256:463fc2903ddaf03f86ff50836c5c63cc696550b0446140159eddfd2e85570c5d", - "size": "2916409" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-win32-0.12.0-esp32-20241016.zip", + "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20241016.zip", + "checksum": "SHA-256:3b5d615e0a72cc771a45dd469031312d5881c01d7b6bc9edb29b8b6bda8c2e90", + "size": "2946244" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-win64-0.12.0-esp32-20240821.zip", - "archiveFileName": "openocd-esp32-win64-0.12.0-esp32-20240821.zip", - "checksum": "SHA-256:550f57369f1f1f6cc600b5dffa3378fd6164d8ea8db7c567cf41091771f090cb", - "size": "2916408" + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-win64-0.12.0-esp32-20241016.zip", + "archiveFileName": "openocd-esp32-win64-0.12.0-esp32-20241016.zip", + "checksum": "SHA-256:5e7b2fd1947d3a8625f6a11db7a2340cf2f41ff4c61284c022c7d7c32b18780a", + "size": "2946244" } ] }, From 38a4c29fedf3c0f681ce8850c107c9d0011a80ec Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Fri, 25 Oct 2024 14:57:21 +0300 Subject: [PATCH 108/406] feature(rtos): Add Tasks status print function (#10515) * feature(rtos): Add Tasks status print function * fix(cmake): Add the new cpp file to CMakeLists * fix(stats): Adjust size of Load column * fix(format): Fix print of runtime formatting * fix(stats): Add license, usage note and C++ guards * fix(stats): Fix formatting and variable names * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- CMakeLists.txt | 1 + cores/esp32/Arduino.h | 1 + cores/esp32/freertos_stats.cpp | 111 +++++++++++++++++++++++++++++++++ cores/esp32/freertos_stats.h | 28 +++++++++ 4 files changed, 141 insertions(+) create mode 100644 cores/esp32/freertos_stats.cpp create mode 100644 cores/esp32/freertos_stats.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9964d85abd0..591b0b31568 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set(CORE_SRCS cores/esp32/esp32-hal-uart.c cores/esp32/esp32-hal-rmt.c cores/esp32/Esp.cpp + cores/esp32/freertos_stats.cpp cores/esp32/FunctionalInterrupt.cpp cores/esp32/HardwareSerial.cpp cores/esp32/HEXBuilder.cpp diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h index 2b115505cff..ab7e497dcf6 100644 --- a/cores/esp32/Arduino.h +++ b/cores/esp32/Arduino.h @@ -199,6 +199,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); #include "Udp.h" #include "HardwareSerial.h" #include "Esp.h" +#include "freertos_stats.h" // Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries using std::abs; diff --git a/cores/esp32/freertos_stats.cpp b/cores/esp32/freertos_stats.cpp new file mode 100644 index 00000000000..50a98bf502b --- /dev/null +++ b/cores/esp32/freertos_stats.cpp @@ -0,0 +1,111 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "freertos_stats.h" +#include "sdkconfig.h" + +#if CONFIG_FREERTOS_USE_TRACE_FACILITY +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/portable.h" +#endif /* CONFIG_FREERTOS_USE_TRACE_FACILITY */ + +void printRunningTasks(Print &printer) { +#if CONFIG_FREERTOS_USE_TRACE_FACILITY +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS +#define FREERTOS_TASK_NUMBER_MAX_NUM 256 // RunTime stats for how many Tasks to be stored + static configRUN_TIME_COUNTER_TYPE ulRunTimeCounters[FREERTOS_TASK_NUMBER_MAX_NUM]; + static configRUN_TIME_COUNTER_TYPE ulLastRunTime = 0; + configRUN_TIME_COUNTER_TYPE ulCurrentRunTime = 0, ulTaskRunTime = 0; +#endif + configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0; + TaskStatus_t *pxTaskStatusArray = NULL; + volatile UBaseType_t uxArraySize = 0, x = 0; + const char *taskStates[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"}; + + // Take a snapshot of the number of tasks in case it changes while this function is executing. + uxArraySize = uxTaskGetNumberOfTasks(); + + // Allocate a TaskStatus_t structure for each task. + pxTaskStatusArray = (TaskStatus_t *)pvPortMalloc(uxArraySize * sizeof(TaskStatus_t)); + + if (pxTaskStatusArray != NULL) { + // Generate raw status information about each task. + uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime); + +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + ulCurrentRunTime = ulTotalRunTime - ulLastRunTime; + ulLastRunTime = ulTotalRunTime; +#endif + printer.printf( + "Tasks: %u" +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + ", Runtime: %lus, Period: %luus" +#endif + "\n", + uxArraySize +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + , + ulTotalRunTime / 1000000, ulCurrentRunTime +#endif + ); + printer.printf("Num\t Name" +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + "\tLoad" +#endif + "\tPrio\t Free" +#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID + "\tCore" +#endif + "\tState\r\n"); + for (x = 0; x < uxArraySize; x++) { +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + if (pxTaskStatusArray[x].xTaskNumber < FREERTOS_TASK_NUMBER_MAX_NUM) { + ulTaskRunTime = (pxTaskStatusArray[x].ulRunTimeCounter - ulRunTimeCounters[pxTaskStatusArray[x].xTaskNumber]); + ulRunTimeCounters[pxTaskStatusArray[x].xTaskNumber] = pxTaskStatusArray[x].ulRunTimeCounter; + ulTaskRunTime = (ulTaskRunTime * 100) / ulCurrentRunTime; // in percentage + } else { + ulTaskRunTime = 0; + } +#endif + printer.printf( + "%3u\t%16s" +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + "\t%3lu%%" +#endif + "\t%4u\t%5lu" +#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID + "\t%4c" +#endif + "\t%s\r\n", + pxTaskStatusArray[x].xTaskNumber, pxTaskStatusArray[x].pcTaskName, +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + ulTaskRunTime, +#endif + pxTaskStatusArray[x].uxCurrentPriority, pxTaskStatusArray[x].usStackHighWaterMark, +#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID + (pxTaskStatusArray[x].xCoreID == tskNO_AFFINITY) ? '*' : ('0' + pxTaskStatusArray[x].xCoreID), +#endif + taskStates[pxTaskStatusArray[x].eCurrentState] + ); + } + + // The array is no longer needed, free the memory it consumes. + vPortFree(pxTaskStatusArray); + printer.println(); + } +#else + printer.println("FreeRTOS trace facility is not enabled."); +#endif /* CONFIG_FREERTOS_USE_TRACE_FACILITY */ +} diff --git a/cores/esp32/freertos_stats.h b/cores/esp32/freertos_stats.h new file mode 100644 index 00000000000..ea9e1a55a21 --- /dev/null +++ b/cores/esp32/freertos_stats.h @@ -0,0 +1,28 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus + +#include "Print.h" + +/* + * Executing this function will cause interrupts and + * the scheduler to be blocked for some time. + * Please use only for debugging purposes. + */ +void printRunningTasks(Print &printer); + +#endif From 9aeb1ba548636070495c132f7e7e82df78387c34 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 25 Oct 2024 09:07:37 -0300 Subject: [PATCH 109/406] ESP32-P4 UART Pin Definitions (#10521) * feat(uart): allow pins_arduino.h to define esp32-p4 uart pins ESP32-P4 has UART default pins only for UART0 and UART1. This PR allows the board definition from pins_arduino.h to define RX2 ... RX4 and TX2 ... TX4 if necessary. It also solves the issue of begin(baud) with no pins for UART2...4 by just sending a error message and returning. * feat(uart): removes the uart2 pin definitions - not existant * fix(uart): solves the case when uart has already been initialized * ci(pre-commit): Apply automatic fixes * fix(ci): uart definition for esp32-p4 uart2 rx,tx pins --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- cores/esp32/HardwareSerial.cpp | 42 ++++++++++++++++++++++++++++++++++ cores/esp32/HardwareSerial.h | 4 ---- tests/validation/uart/uart.ino | 8 +++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index a6a7573f6e3..fb93dad1c47 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -313,6 +313,11 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in // map logical pins to GPIO numbers rxPin = digitalPinToGPIONumber(rxPin); txPin = digitalPinToGPIONumber(txPin); + int8_t _rxPin = uart_get_RxPin(_uart_nr); + int8_t _txPin = uart_get_TxPin(_uart_nr); + + rxPin = rxPin < 0 ? _rxPin : rxPin; + txPin = txPin < 0 ? _txPin : txPin; HSERIAL_MUTEX_LOCK(); // First Time or after end() --> set default Pins @@ -341,14 +346,51 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in case UART_NUM_2: if (rxPin < 0 && txPin < 0) { // do not change RX2/TX2 if it has already been set before +#ifdef RX2 rxPin = _rxPin < 0 ? (int8_t)RX2 : _rxPin; +#endif +#ifdef TX2 txPin = _txPin < 0 ? (int8_t)TX2 : _txPin; +#endif + } + break; +#endif +#if SOC_UART_HP_NUM > 3 // may save some flash bytes... + case UART_NUM_3: + if (rxPin < 0 && txPin < 0) { + // do not change RX2/TX2 if it has already been set before +#ifdef RX3 + rxPin = _rxPin < 0 ? (int8_t)RX3 : _rxPin; +#endif +#ifdef TX3 + txPin = _txPin < 0 ? (int8_t)TX3 : _txPin; +#endif + } + break; +#endif +#if SOC_UART_HP_NUM > 4 // may save some flash bytes... + case UART_NUM_4: + if (rxPin < 0 && txPin < 0) { + // do not change RX2/TX2 if it has already been set before +#ifdef RX4 + rxPin = _rxPin < 0 ? (int8_t)RX4 : _rxPin; +#endif +#ifdef TX4 + txPin = _txPin < 0 ? (int8_t)TX4 : _txPin; +#endif } break; #endif } } + // if no RX/TX pins are defined, it will not start the UART driver + if (rxPin < 0 && txPin < 0) { + log_e("No RX/TX pins defined. Please set RX/TX pins."); + HSERIAL_MUTEX_UNLOCK(); + return; + } + // IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified. // it will detach previous UART attached pins diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 8eb7f2c91a6..a33d5def34d 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -200,8 +200,6 @@ typedef enum { #define RX2 (gpio_num_t)4 #elif CONFIG_IDF_TARGET_ESP32S3 #define RX2 (gpio_num_t)19 -#elif CONFIG_IDF_TARGET_ESP32P4 -#define RX2 (gpio_num_t)15 #endif #endif @@ -210,8 +208,6 @@ typedef enum { #define TX2 (gpio_num_t)25 #elif CONFIG_IDF_TARGET_ESP32S3 #define TX2 (gpio_num_t)20 -#elif CONFIG_IDF_TARGET_ESP32P4 -#define TX2 (gpio_num_t)14 #endif #endif #endif /* SOC_UART_HP_NUM > 2 */ diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index e5fa0a8285f..01c449867db 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -52,6 +52,14 @@ #define NEW_TX1 10 #endif +// ESP32-P4 has no UART pin definition for RX2, TX2, RX3, TX3, RX4, TX4 +#ifndef RX2 +#define RX2 RX1 +#endif +#ifndef TX2 +#define TX2 RX1 +#endif + /* Utility global variables */ static String recv_msg = ""; From 74e4a744ce0bae127cd2eeac04e62c2bf45a9c93 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 25 Oct 2024 14:48:35 -0300 Subject: [PATCH 110/406] feat(uart): uart break example improvement (#10525) prints the HEXA and CHAR in order to allow the user to see why there is 1 extra char (0x00) when BREAK is received. --- .../OnReceiveError_BREAK_Demo/OnReceiveError_BREAK_Demo.ino | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/ESP32/examples/Serial/OnReceiveError_BREAK_Demo/OnReceiveError_BREAK_Demo.ino b/libraries/ESP32/examples/Serial/OnReceiveError_BREAK_Demo/OnReceiveError_BREAK_Demo.ino index fb7af04c5f5..209cf8922be 100644 --- a/libraries/ESP32/examples/Serial/OnReceiveError_BREAK_Demo/OnReceiveError_BREAK_Demo.ino +++ b/libraries/ESP32/examples/Serial/OnReceiveError_BREAK_Demo/OnReceiveError_BREAK_Demo.ino @@ -80,7 +80,11 @@ void onReceiveFunction() { received_bytes = received_bytes + available; Serial.printf("onReceive Callback:: There are %d bytes available: {", available); while (available--) { - Serial.print((char)Serial1.read()); + char c = Serial1.read(); + Serial.printf("0x%x='%c'", c, c); + if (available) { + Serial.print(" "); + } } Serial.println("}"); } From a805e0696c6564d356b2a1dc616af08394d082d4 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:49:05 -0300 Subject: [PATCH 111/406] feat(esptool): Update esptool to v4.8.1 (#10524) * feat(esptool): Update esptool to v4.8.1 * fix(archives): Fix checksums --- package/package_esp32_index.template.json | 44 +++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index aafaa211eba..9681cf54c98 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -72,7 +72,7 @@ { "packager": "esp32", "name": "esptool_py", - "version": "4.6" + "version": "4.8.1" }, { "packager": "esp32", @@ -460,42 +460,42 @@ }, { "name": "esptool_py", - "version": "4.8.0", + "version": "4.8.1", "systems": [ { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-linux-amd64.zip", - "archiveFileName": "esptool-v4.8.0-linux-amd64.zip", - "checksum": "SHA-256:e637adc204b74b980013e89dafce6e056401ec26c94e205b0158075a836c56c6", - "size": "64617780" + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC1/esptool-v4.8.1-linux-amd64.tar.gz", + "archiveFileName": "esptool-v4.8.1-linux-amd64.tar.gz", + "checksum": "SHA-256:aaaaa25e1c64442ae93604812376783dbc50f34536221b5897456e12f01e1bfd", + "size": "64635657" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-linux-arm64.zip", - "archiveFileName": "esptool-v4.8.0-linux-arm64.zip", - "checksum": "SHA-256:c3a7749bed8d1929b0ad35743cc5557d60ecb81a10ffac28cb55ed1545e0223a", - "size": "54432155" + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC1/esptool-v4.8.1-linux-arm64.tar.gz", + "archiveFileName": "esptool-v4.8.1-linux-arm64.tar.gz", + "checksum": "SHA-256:76170a9282bdc52fddd75e4498fd6bee55fe19088a34ab363b3aeff800d73f60", + "size": "54449306" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-linux-arm32.zip", - "archiveFileName": "esptool-v4.8.0-linux-arm32.zip", - "checksum": "SHA-256:b781a86b53a17d24e02996c0a7958f9b76f6873fc1cc07c64ab6326e19395570", - "size": "45858426" + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC1/esptool-v4.8.1-linux-arm32.tar.gz", + "archiveFileName": "esptool-v4.8.1-linux-arm32.tar.gz", + "checksum": "SHA-256:26b842e22a66b3d01e830a4784686a69cfb107d774a4093327ec6bba7bb17794", + "size": "45868720" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-macos.zip", - "archiveFileName": "esptool-v4.8.0-macos.zip", - "checksum": "SHA-256:73bba755d2da15ef18b8b8d8fe37c459d296648efb02d5449a3fc0035930306a", - "size": "29821710" + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC1/esptool-v4.8.1-macos.tar.gz", + "archiveFileName": "esptool-v4.8.1-macos.tar.gz", + "checksum": "SHA-256:6e1fc5ea04490e849c925c48d5cee590164fcf9b9bd419a7b014c2fb48a13743", + "size": "29828542" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esptool/releases/download/v4.8.0/esptool-v4.8.0-win64.zip", - "archiveFileName": "esptool-v4.8.0-win64.zip", - "checksum": "SHA-256:5575beabfe8c1c1ea7c1a0f1bd42ee97ac3f4c4dae5fc74cda58be0e23016da3", - "size": "33608471" + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC1/esptool-v4.8.1-win64.zip", + "archiveFileName": "esptool-v4.8.1-win64.zip", + "checksum": "SHA-256:3e97fb990fdd721b923b478eaaa046967c7919dbc9cbd04c445307571177918a", + "size": "33612728" } ] }, From 87ad78d787ebd8cb1638642d6c70d2b335f0be90 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 29 Oct 2024 13:10:20 +0200 Subject: [PATCH 112/406] fix(bm): Board Manager install will fail on Windows (#10533) * fix(bm): Board Manager install will fail on Windows On some Windows installations, Board Manager will fail to install the RC2 core, because it could not find esptool for the given OS. * fix(package): EspTool for Mac is only ARM64 version cc: @lucasssvaz --- package/package_esp32_index.template.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 9681cf54c98..5f05469a185 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -484,12 +484,19 @@ "size": "45868720" }, { - "host": "x86_64-apple-darwin", + "host": "arm64-apple-darwin", "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC1/esptool-v4.8.1-macos.tar.gz", "archiveFileName": "esptool-v4.8.1-macos.tar.gz", "checksum": "SHA-256:6e1fc5ea04490e849c925c48d5cee590164fcf9b9bd419a7b014c2fb48a13743", "size": "29828542" }, + { + "host": "i686-mingw32", + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC1/esptool-v4.8.1-win64.zip", + "archiveFileName": "esptool-v4.8.1-win64.zip", + "checksum": "SHA-256:3e97fb990fdd721b923b478eaaa046967c7919dbc9cbd04c445307571177918a", + "size": "33612728" + }, { "host": "x86_64-mingw32", "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC1/esptool-v4.8.1-win64.zip", From d47771f2cc649c3cd52a3f6eb3d9b97c82005ffb Mon Sep 17 00:00:00 2001 From: Mathieu Carbou Date: Tue, 29 Oct 2024 12:10:40 +0100 Subject: [PATCH 113/406] fix(sntp): Lock / Unlock LWIP if CONFIG_LWIP_TCPIP_CORE_LOCKING is set (#10529) * fix(sntp): Lock / Unlock LWIP if CONFIG_LWIP_TCPIP_CORE_LOCKING is set Fixes: https://github.com/espressif/arduino-esp32/issues/10526 * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- cores/esp32/esp32-hal-time.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/cores/esp32/esp32-hal-time.c b/cores/esp32/esp32-hal-time.c index 23bd3bf9e99..25c060eabdd 100644 --- a/cores/esp32/esp32-hal-time.c +++ b/cores/esp32/esp32-hal-time.c @@ -17,6 +17,10 @@ //#include "tcpip_adapter.h" #include "esp_netif.h" +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING +#include "lwip/priv/tcpip_priv.h" +#endif + static void setTimeZone(long offset, int daylight) { char cst[17] = {0}; char cdt[17] = "DST"; @@ -50,11 +54,25 @@ void configTime(long gmtOffset_sec, int daylightOffset_sec, const char *server1, if (sntp_enabled()) { sntp_stop(); } + +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING + if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { + LOCK_TCPIP_CORE(); + } +#endif + sntp_setoperatingmode(SNTP_OPMODE_POLL); sntp_setservername(0, (char *)server1); sntp_setservername(1, (char *)server2); sntp_setservername(2, (char *)server3); sntp_init(); + +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING + if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { + UNLOCK_TCPIP_CORE(); + } +#endif + setTimeZone(-gmtOffset_sec, daylightOffset_sec); } @@ -68,11 +86,25 @@ void configTzTime(const char *tz, const char *server1, const char *server2, cons if (sntp_enabled()) { sntp_stop(); } + +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING + if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { + LOCK_TCPIP_CORE(); + } +#endif + sntp_setoperatingmode(SNTP_OPMODE_POLL); sntp_setservername(0, (char *)server1); sntp_setservername(1, (char *)server2); sntp_setservername(2, (char *)server3); sntp_init(); + +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING + if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { + UNLOCK_TCPIP_CORE(); + } +#endif + setenv("TZ", tz, 1); tzset(); } From 05102fe853fea3687ddf9c4f3adf51aa168a5219 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Thu, 31 Oct 2024 08:13:08 -0300 Subject: [PATCH 114/406] docs(lib-builder): Improve UI and Docker image sections (#10535) * docs(lib-builder): Improve UI and Docker image sections * docs(lib-builder): Apply review suggestions --- docs/en/lib_builder.rst | 72 +++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/docs/en/lib_builder.rst b/docs/en/lib_builder.rst index 3d28761ab2d..a05fd45d584 100644 --- a/docs/en/lib_builder.rst +++ b/docs/en/lib_builder.rst @@ -204,6 +204,50 @@ You can then run the UI using the following command: ./tools/config_editor/app.py +Pre-Configuring the UI +********************** + +The UI can be pre-configured using command line arguments. The following arguments are available: + +- ``-t, --target ``: Comma-separated list of targets to be compiled. + Choose from: *all*, *esp32*, *esp32s2*, *esp32s3*, *esp32c2*, *esp32c3*, *esp32c6*, *esp32h2*. Default: all except *esp32c2*; +- ``--copy, --no-copy``: Enable/disable copying the compiled libraries to ``arduino-esp32``. Enabled by default; +- ``-c, --arduino-path ``: Path to ``arduino-esp32`` directory. Default: OS dependent; +- ``-A, --arduino-branch ``: Branch of the ``arduino-esp32`` repository to be used. Default: set by the build script; +- ``-I, --idf-branch ``: Branch of the ``ESP-IDF`` repository to be used. Default: set by the build script; +- ``-i, --idf-commit ``: Commit of the ``ESP-IDF`` repository to be used. Default: set by the build script; +- ``-D, --debug-level ``: Debug level to be set in ``ESP-IDF``. + Choose from: *default*, *none*, *error*, *warning*, *info*, *debug*, *verbose*. Default: *default*. + +Please note that all these options can be changed in the UI itself and are only used for automation purposes. + +Screens +******* + +There are many screens in the UI that are used to configure the libraries to be compiled. +Note that in all screens you can also use the shortcut keys shown in the footer bar to navigate. + +The UI consists of the following screens: + +- **Main Menu**: The main screen shows buttons to navigate to the other screens. +- **Compile Screen**: The compile screen shows the output of the compilation process and any errors that may have occurred. +- **Sdkconfig Editor**: The sdkconfig editor screen is a simple text editor that shows you the sdkconfig files that will be used for compilation. + You can edit the files here to customize the generated libraries. +- **Settings Screen**: The settings screen allows you to change the settings of the compilation process. + Here you can change: + + - The targets that the libraries will be compiled for. To save time, you can compile the libraries only for the target you are using; + - Whether the compiled libraries will be copied to the ``arduino-esp32`` directory after compilation so that they can be used in the Arduino IDE; + - The path to the ``arduino-esp32`` directory. This will be automatically set if the ``arduino-esp32`` repository is in one of the default locations. + If not, you can set it manually here. If using the docker image, it should not be changed as the mount point is fixed; + - The branch of the ``arduino-esp32`` repository to be used. This is useful if you want to compile the libraries for a + specific branch or pull request of the ``arduino-esp32`` repository. Leave empty to use the default branch for this ``ESP-IDF`` version; + - The branch of the ``ESP-IDF`` repository to be used. This is useful if you want to compile the libraries for a specific branch of the ``ESP-IDF`` repository. + Leave empty to use the default branch for this IDF version; + - The commit of the ``ESP-IDF`` repository to be used. This is useful if you want to compile the libraries for a specific commit on the selected branch. + Leave empty to use the latest commit; + - The debug level to be set in ``ESP-IDF``. + Docker Image ------------ @@ -224,8 +268,9 @@ Tags Multiple tags of this image are maintained: -- ``latest``: tracks ``master`` branch of the Lib Builder -- ``release-vX.Y``: tracks ``release/vX.Y`` branch of the Lib Builder +- ``latest``: tracks ``master`` branch of the Lib Builder. Note that the ``latest`` tag is not recommended for use as, depending on the + development stage of the Lib Builder, it might not be stable or might not contain the latest changes; +- ``release-vX.Y``: tracks ``release/vX.Y`` branch of the Lib Builder. .. note:: Versions of Lib Builder released before this feature was introduced do not have corresponding Docker image versions. @@ -234,7 +279,7 @@ Multiple tags of this image are maintained: Usage ***** -Before using the ``espressif/esp32-arduino-lib-builder`` Docker image locally, make sure you have Docker installed. +Before using the ``espressif/esp32-arduino-lib-builder`` Docker image locally, make sure you have Docker installed and running on your machine. Follow the instructions at https://docs.docker.com/install/, if it is not installed yet. If using the image in a CI environment, consult the documentation of your CI service on how to specify the image used for the build process. @@ -248,7 +293,7 @@ To run the Docker image manually, use the following command from the root of the .. code-block:: bash - docker run --rm -it -v $PWD:/arduino-esp32 -e TERM=xterm-256color espressif/esp32-arduino-lib-builder + docker run --rm -it -v $PWD:/arduino-esp32 -e TERM=xterm-256color espressif/esp32-arduino-lib-builder:release-v5.1 This will start the Lib Builder UI for compiling the libraries. The above command explained: @@ -258,7 +303,8 @@ This will start the Lib Builder UI for compiling the libraries. The above comman - ``-t`` Allocate a pseudo-TTY; - ``-e TERM=xterm-256color``: Optional. Sets the terminal type to ``xterm-256color`` to display colors correctly; - ``-v $PWD:/arduino-esp32``: Optional. Mounts the current folder at ``/arduino-esp32`` inside the container. If not provided, the container will not copy the compiled libraries to the host machine; -- ``espressif/esp32-arduino-lib-builder``: uses Docker image ``espressif/esp32-arduino-lib-builder`` with tag ``latest``. The ``latest`` tag is implicitly added by Docker when no tag is specified. +- ``espressif/esp32-arduino-lib-builder:release-v5.1``: uses Docker image ``espressif/esp32-arduino-lib-builder`` with tag ``release-v5.1``. + The ``latest`` tag is implicitly added by Docker when no tag is specified. It is recommended to use a specific version tag to ensure reproducibility of the build process. .. warning:: The ``-v`` option is used to mount a folder from the host machine to the container. Make sure the folder already exists on the host machine before running the command. @@ -278,14 +324,15 @@ For example, to run a terminal inside the container, you can run: .. code-block:: bash - docker run -it espressif/esp32-arduino-lib-builder:latest /bin/bash + docker run -it espressif/esp32-arduino-lib-builder:release-v5.1 /bin/bash Running the Docker image using the provided run script will depend on the host OS. -Use the following command from the root of the ``arduino-esp32`` repository to execute the image in a Linux or macOS environment: +Use the following command from the root of the ``arduino-esp32`` repository to execute the image in a Linux or macOS environment for +the ``release-v5.1`` tag: .. code-block:: bash - curl -LJO https://raw.githubusercontent.com/espressif/esp32-arduino-lib-builder/master/tools/docker/run.sh + curl -LJO https://raw.githubusercontent.com/espressif/esp32-arduino-lib-builder/refs/heads/release/v5.1/tools/docker/run.sh chmod +x run.sh ./run.sh $PWD @@ -293,9 +340,16 @@ For Windows, use the following command in PowerShell from the root of the ``ardu .. code-block:: powershell - Invoke-WebRequest -Uri "https://raw.githubusercontent.com/espressif/esp32-arduino-lib-builder/master/tools/docker/run.ps1" -OutFile "run.ps1" + Invoke-WebRequest -Uri "https://raw.githubusercontent.com/espressif/esp32-arduino-lib-builder/refs/heads/release/v5.1/tools/docker/run.ps1" -OutFile "run.ps1" .\run.ps1 $pwd +As the script is unsigned, you may need to change the execution policy of the current session before running the script. +To do so, run the following command in PowerShell: + +.. code-block:: powershell + + Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass + .. warning:: It is always a good practice to understand what the script does before running it. Make sure to analyze the content of the script to ensure it is safe to run and won't cause any harm to your system. From eeecf844a7cfc4f0e019777c7da8979946993178 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:12:20 -0300 Subject: [PATCH 115/406] ci(workflows): General improvements and fixes (#10544) * ci(triggers): Improve workflow triggering and bump versions * ci(runtime): Improve runtime tests triggers * fix(push): Fix push chunks script indentation and lib detection --- .github/scripts/set_push_chunks.sh | 116 ++++++++++++++--------------- .github/workflows/pre-commit.yml | 14 +++- .github/workflows/push.yml | 6 +- .github/workflows/tests.yml | 7 +- tests/requirements.txt | 8 +- tools/pre-commit/requirements.txt | 2 +- 6 files changed, 81 insertions(+), 72 deletions(-) diff --git a/.github/scripts/set_push_chunks.sh b/.github/scripts/set_push_chunks.sh index 472205f0c38..11a93a7159d 100644 --- a/.github/scripts/set_push_chunks.sh +++ b/.github/scripts/set_push_chunks.sh @@ -4,73 +4,73 @@ build_all=false chunks_count=0 if [[ $CORE_CHANGED == 'true' ]] || [[ $IS_PR != 'true' ]]; then - echo "Core files changed or not a PR. Building all." - build_all=true - chunks_count=$MAX_CHUNKS + echo "Core files changed or not a PR. Building all." + build_all=true + chunks_count=$MAX_CHUNKS elif [[ $LIB_CHANGED == 'true' ]]; then - echo "Libraries changed. Building only affected sketches." - if [[ $NETWORKING_CHANGED == 'true' ]]; then - echo "Networking libraries changed. Building networking related sketches." - networking_sketches="$(find libraries/WiFi -name *.ino) " - networking_sketches+="$(find libraries/Ethernet -name *.ino) " - networking_sketches+="$(find libraries/PPP -name *.ino) " - networking_sketches+="$(find libraries/NetworkClientSecure -name *.ino) " - networking_sketches+="$(find libraries/WebServer -name *.ino) " - fi - if [[ $FS_CHANGED == 'true' ]]; then - echo "FS libraries changed. Building FS related sketches." - fs_sketches="$(find libraries/SD -name *.ino) " - fs_sketches+="$(find libraries/SD_MMC -name *.ino) " - fs_sketches+="$(find libraries/SPIFFS -name *.ino) " - fs_sketches+="$(find libraries/LittleFS -name *.ino) " - fs_sketches+="$(find libraries/FFat -name *.ino) " - fi - sketches="$networking_sketches $fs_sketches" - for file in $LIB_FILES; do - if [[ $file == *.ino ]]; then - # If file ends with .ino, add it to the list of sketches - echo "Sketch found: $file" - sketches+="$file " - elif [[ $(basename $(dirname $file)) == "src" ]]; then - # If file is in a src directory, find all sketches in the parent/examples directory - echo "Library src file found: $file" - lib=$(dirname $(dirname $file)) - if [[ -d $lib/examples ]]; then - lib_sketches=$(find $lib/examples -name *.ino) - sketches+="$lib_sketches " - echo "Library sketches: $lib_sketches" - fi - else - # If file is in a example folder but it is not a sketch, find all sketches in the current directory - echo "File in example folder found: $file" - sketch=$(find $(dirname $file) -name *.ino) - sketches+="$sketch " - echo "Sketch in example folder: $sketch" - fi - echo "" - done + echo "Libraries changed. Building only affected sketches." + if [[ $NETWORKING_CHANGED == 'true' ]]; then + echo "Networking libraries changed. Building networking related sketches." + networking_sketches="$(find libraries/WiFi -name *.ino) " + networking_sketches+="$(find libraries/Ethernet -name *.ino) " + networking_sketches+="$(find libraries/PPP -name *.ino) " + networking_sketches+="$(find libraries/NetworkClientSecure -name *.ino) " + networking_sketches+="$(find libraries/WebServer -name *.ino) " + fi + if [[ $FS_CHANGED == 'true' ]]; then + echo "FS libraries changed. Building FS related sketches." + fs_sketches="$(find libraries/SD -name *.ino) " + fs_sketches+="$(find libraries/SD_MMC -name *.ino) " + fs_sketches+="$(find libraries/SPIFFS -name *.ino) " + fs_sketches+="$(find libraries/LittleFS -name *.ino) " + fs_sketches+="$(find libraries/FFat -name *.ino) " + fi + sketches="$networking_sketches $fs_sketches" + for file in $LIB_FILES; do + lib=$(echo $file | awk -F "/" '{print $1"/"$2}') + if [[ "$file" == *.ino ]]; then + # If file ends with .ino, add it to the list of sketches + echo "Sketch found: $file" + sketches+="$file " + elif [[ "$file" == "$lib/src/"* ]]; then + # If file is inside the src directory, find all sketches in the lib/examples directory + echo "Library src file found: $file" + if [[ -d $lib/examples ]]; then + lib_sketches=$(find $lib/examples -name *.ino) + sketches+="$lib_sketches " + echo "Library sketches: $lib_sketches" + fi + else + # If file is in a example folder but it is not a sketch, find all sketches in the current directory + echo "File in example folder found: $file" + sketch=$(find $(dirname $file) -name *.ino) + sketches+="$sketch " + echo "Sketch in example folder: $sketch" + fi + echo "" + done fi if [[ -n $sketches ]]; then - # Remove duplicates - sketches=$(echo $sketches | tr ' ' '\n' | sort | uniq) - for sketch in $sketches; do - echo $sketch >> sketches_found.txt - chunks_count=$((chunks_count+1)) - done - echo "Number of sketches found: $chunks_count" - echo "Sketches:" - echo "$sketches" + # Remove duplicates + sketches=$(echo $sketches | tr ' ' '\n' | sort | uniq) + for sketch in $sketches; do + echo $sketch >> sketches_found.txt + chunks_count=$((chunks_count+1)) + done + echo "Number of sketches found: $chunks_count" + echo "Sketches:" + echo "$sketches" - if [[ $chunks_count -gt $MAX_CHUNKS ]]; then - echo "More sketches than the allowed number of chunks found. Limiting to $MAX_CHUNKS chunks." - chunks_count=$MAX_CHUNKS - fi + if [[ $chunks_count -gt $MAX_CHUNKS ]]; then + echo "More sketches than the allowed number of chunks found. Limiting to $MAX_CHUNKS chunks." + chunks_count=$MAX_CHUNKS + fi fi chunks='["0"' for i in $(seq 1 $(( $chunks_count - 1 )) ); do - chunks+=",\"$i\"" + chunks+=",\"$i\"" done chunks+="]" diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index c4ae017c229..8257e78c822 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -6,7 +6,7 @@ on: branches: - master pull_request: - types: [opened, reopened, synchronize, labeled, unlabeled] + types: [opened, reopened, synchronize, labeled] concurrency: group: pre-commit-${{github.event.pull_request.number || github.ref}} @@ -15,8 +15,10 @@ concurrency: jobs: lint: if: | + github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'Status: Pending Merge') || - github.event_name != 'pull_request' + contains(github.event.pull_request.labels.*.name, 'Re-trigger Pre-commit Hooks') + name: Check if fixes are needed runs-on: ubuntu-latest steps: @@ -25,6 +27,12 @@ jobs: with: fetch-depth: 2 + - name: Remove Label + if: contains(github.event.pull_request.labels.*.name, 'Re-trigger Pre-commit Hooks') + run: gh pr edit ${{ github.event.number }} --remove-label 'Re-trigger Pre-commit Hooks' + env: + GH_TOKEN: ${{ github.token }} + - name: Set up Python 3 uses: actions/setup-python@v5 with: @@ -65,7 +73,7 @@ jobs: key: ${{ steps.restore-cache.outputs.cache-primary-key }} - name: Push changes using pre-commit-ci-lite - uses: pre-commit-ci/lite-action@v1.0.2 + uses: pre-commit-ci/lite-action@v1.1.0 # Only push changes in PRs if: ${{ always() && github.event_name == 'pull_request' }} with: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 19e53b844f2..82159e1b8a4 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -5,7 +5,7 @@ on: push: branches: - master - - release/v2.x + - release/* pull_request: paths: - 'cores/**' @@ -47,6 +47,7 @@ jobs: cmake-check: name: Check cmake file runs-on: ubuntu-latest + if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }} steps: - uses: actions/checkout@v4 - run: bash ./.github/scripts/check-cmakelists.sh @@ -54,6 +55,7 @@ jobs: gen-chunks: name: Generate chunks runs-on: ubuntu-latest + if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }} outputs: build_all: ${{ steps.set-chunks.outputs.build_all }} build_libraries: ${{ steps.set-chunks.outputs.build_libraries }} @@ -307,7 +309,7 @@ jobs: #Upload PR number as artifact upload-pr-number: name: Upload PR number - if: github.event_name == 'pull_request' + if: ${{ github.event_name == 'pull_request' && !startsWith(github.head_ref, 'release/') }} runs-on: ubuntu-latest steps: - name: Save the PR number in an artifact diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ab8baa6d14c..f57a1925c1c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,10 +26,9 @@ on: - '!.github/scripts/upload_py_tools.sh' - 'tests/**' - 'cores/**' - - 'libraries/**' - - '!libraries/**.md' - - '!libraries/**.txt' - - '!libraries/**.properties' + - 'libraries/*/src/**.cpp' + - 'libraries/*/src/**.h' + - 'libraries/*/src/**.c' - 'package/**' schedule: - cron: '0 2 * * *' diff --git a/tests/requirements.txt b/tests/requirements.txt index 63d204a96b0..a7df8928665 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,7 +1,7 @@ cryptography==43.0.1 --only-binary cryptography pytest-cov==5.0.0 -pytest-embedded-serial-esp==1.11.6 -pytest-embedded-arduino==1.11.6 -pytest-embedded-wokwi==1.11.6 -pytest-embedded-qemu==1.11.6 +pytest-embedded-serial-esp==1.11.8 +pytest-embedded-arduino==1.11.8 +pytest-embedded-wokwi==1.11.8 +pytest-embedded-qemu==1.11.8 diff --git a/tools/pre-commit/requirements.txt b/tools/pre-commit/requirements.txt index 7b88387b05b..aca4a61191f 100644 --- a/tools/pre-commit/requirements.txt +++ b/tools/pre-commit/requirements.txt @@ -1,2 +1,2 @@ -pre-commit==3.7.1 +pre-commit==4.0.1 docutils==0.16 From 57d0deef2dfaf916e9ad93bdeaab0442433109db Mon Sep 17 00:00:00 2001 From: wurongmin <55608753+wurongmin@users.noreply.github.com> Date: Tue, 5 Nov 2024 05:42:19 +0800 Subject: [PATCH 116/406] feat(boards): add Waveshare ESP32-S3-Touch-AMOLED boards (#10549) * Add files via upload * Add files via upload * feat(boards): add Waveshare ESP32-S3-Touch-AMOLED boards Added three micro snow development boards to boards * feat(boards): add Waveshare ESP32-S3-Touch-AMOLED variants A trio of micro-snow variants have been added to the variants * Delete variants/waveshare_esp32_s3_touch_amoled_143/pins_arduino.h * Delete variants/waveshare_esp32_s3_touch_amoled_164 directory * Delete variants/waveshare_esp32_s3_touch_amoled_191 directory * feat(boards): Three variants of the development board were added waveshare_esp32_s3_touch_amoled_143 waveshare_esp32_s3_touch_amoled_164 waveshare_esp32_s3_touch_amoled_191 * feat(boards): Add three boards to boards * feat(boards): Add the variants * feat(boards): Fixed the boards file To ensure that each plate type only one * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- boards.txt | 606 ++++++++++++++++++ .../pins_arduino.h | 49 ++ .../pins_arduino.h | 55 ++ .../pins_arduino.h | 57 ++ 4 files changed, 767 insertions(+) create mode 100644 variants/waveshare_esp32_s3_touch_amoled_143/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_amoled_164/pins_arduino.h create mode 100644 variants/waveshare_esp32_s3_touch_amoled_191/pins_arduino.h diff --git a/boards.txt b/boards.txt index 8d4cc529ed7..9bb3f53b7bf 100644 --- a/boards.txt +++ b/boards.txt @@ -46266,3 +46266,609 @@ waveshare_esp32_s3_relay_6ch.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MOD waveshare_esp32_s3_relay_6ch.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port ############################################################## + +waveshare_esp32_s3_touch_amoled_164.name=Waveshare ESP32-S3-Touch-AMOLED-1.64 +waveshare_esp32_s3_touch_amoled_164.vid.0=0x303a +waveshare_esp32_s3_touch_amoled_164.pid.0=0x8249 +waveshare_esp32_s3_touch_amoled_164.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_amoled_164.upload_port.0.pid=0x8249 + +waveshare_esp32_s3_touch_amoled_164.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_amoled_164.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_amoled_164.upload.tool=esptool_py +waveshare_esp32_s3_touch_amoled_164.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_amoled_164.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_amoled_164.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_amoled_164.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_amoled_164.upload.flags= +waveshare_esp32_s3_touch_amoled_164.upload.extra_flags= +waveshare_esp32_s3_touch_amoled_164.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_amoled_164.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_amoled_164.serial.disableDTR=false +waveshare_esp32_s3_touch_amoled_164.serial.disableRTS=false + +waveshare_esp32_s3_touch_amoled_164.build.tarch=xtensa +waveshare_esp32_s3_touch_amoled_164.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_amoled_164.build.target=esp32s3 +waveshare_esp32_s3_touch_amoled_164.build.mcu=esp32s3 +waveshare_esp32_s3_touch_amoled_164.build.core=esp32 +waveshare_esp32_s3_touch_amoled_164.build.variant=waveshare_esp32_s3_touch_amoled_164 +waveshare_esp32_s3_touch_amoled_164.build.board=WAVESHARE_ESP32_S3_TOUCH_AMOLED_164 + +waveshare_esp32_s3_touch_amoled_164.build.usb_mode=1 +waveshare_esp32_s3_touch_amoled_164.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_amoled_164.build.msc_on_boot=0 +waveshare_esp32_s3_touch_amoled_164.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_amoled_164.build.f_cpu=240000000L +waveshare_esp32_s3_touch_amoled_164.build.flash_size=16MB + +waveshare_esp32_s3_touch_amoled_164.build.flash_freq=80m +waveshare_esp32_s3_touch_amoled_164.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_164.build.boot=qio +waveshare_esp32_s3_touch_amoled_164.build.boot_freq=80m +waveshare_esp32_s3_touch_amoled_164.build.partitions=default +waveshare_esp32_s3_touch_amoled_164.build.defines= +waveshare_esp32_s3_touch_amoled_164.build.loop_core= +waveshare_esp32_s3_touch_amoled_164.build.event_core= +waveshare_esp32_s3_touch_amoled_164.build.psram_type=qspi +waveshare_esp32_s3_touch_amoled_164.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_amoled_164.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_amoled_164.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_amoled_164.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_amoled_164.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_amoled_164.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_amoled_164.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_amoled_164.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_amoled_164.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_amoled_164.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_amoled_164.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_amoled_164.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_amoled_164.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_amoled_164.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_amoled_164.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_amoled_164.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_amoled_164.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_amoled_164.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_amoled_164.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_amoled_164.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_amoled_164.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_164.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_amoled_164.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_amoled_164.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_amoled_164.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_164.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_amoled_164.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_amoled_164.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_amoled_164.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_164.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_amoled_164.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_amoled_164.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_amoled_164.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_amoled_164.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_amoled_164.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_amoled_164.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_amoled_164.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_amoled_164.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) + +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 + +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_amoled_164.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_amoled_164.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_amoled_164.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_amoled_164.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_amoled_164.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_amoled_164.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_amoled_164.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_amoled_164.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + +waveshare_esp32_s3_touch_amoled_143.name=Waveshare ESP32-S3-Touch-AMOLED-1.43 +waveshare_esp32_s3_touch_amoled_143.vid.0=0x303a +waveshare_esp32_s3_touch_amoled_143.pid.0=0x824a +waveshare_esp32_s3_touch_amoled_143.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_amoled_143.upload_port.0.pid=0x824a + +waveshare_esp32_s3_touch_amoled_143.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_amoled_143.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_amoled_143.upload.tool=esptool_py +waveshare_esp32_s3_touch_amoled_143.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_amoled_143.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_amoled_143.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_amoled_143.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_amoled_143.upload.flags= +waveshare_esp32_s3_touch_amoled_143.upload.extra_flags= +waveshare_esp32_s3_touch_amoled_143.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_amoled_143.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_amoled_143.serial.disableDTR=false +waveshare_esp32_s3_touch_amoled_143.serial.disableRTS=false + +waveshare_esp32_s3_touch_amoled_143.build.tarch=xtensa +waveshare_esp32_s3_touch_amoled_143.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_amoled_143.build.target=esp32s3 +waveshare_esp32_s3_touch_amoled_143.build.mcu=esp32s3 +waveshare_esp32_s3_touch_amoled_143.build.core=esp32 +waveshare_esp32_s3_touch_amoled_143.build.variant=waveshare_esp32_s3_touch_amoled_143 +waveshare_esp32_s3_touch_amoled_143.build.board=WAVESHARE_ESP32_S3_TOUCH_AMOLED_143 + +waveshare_esp32_s3_touch_amoled_143.build.usb_mode=1 +waveshare_esp32_s3_touch_amoled_143.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_amoled_143.build.msc_on_boot=0 +waveshare_esp32_s3_touch_amoled_143.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_amoled_143.build.f_cpu=240000000L +waveshare_esp32_s3_touch_amoled_143.build.flash_size=16MB + +waveshare_esp32_s3_touch_amoled_143.build.flash_freq=80m +waveshare_esp32_s3_touch_amoled_143.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_143.build.boot=qio +waveshare_esp32_s3_touch_amoled_143.build.boot_freq=80m +waveshare_esp32_s3_touch_amoled_143.build.partitions=default +waveshare_esp32_s3_touch_amoled_143.build.defines= +waveshare_esp32_s3_touch_amoled_143.build.loop_core= +waveshare_esp32_s3_touch_amoled_143.build.event_core= +waveshare_esp32_s3_touch_amoled_143.build.psram_type=qspi +waveshare_esp32_s3_touch_amoled_143.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_amoled_143.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_amoled_143.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_amoled_143.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_amoled_143.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_amoled_143.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_amoled_143.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_amoled_143.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_amoled_143.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_amoled_143.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_amoled_143.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_amoled_143.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_amoled_143.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_amoled_143.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_amoled_143.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_amoled_143.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_amoled_143.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_amoled_143.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_amoled_143.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_amoled_143.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_amoled_143.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_143.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_amoled_143.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_amoled_143.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_amoled_143.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_143.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_amoled_143.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_amoled_143.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_amoled_143.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_143.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_amoled_143.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_amoled_143.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_amoled_143.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_amoled_143.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_amoled_143.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_amoled_143.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_amoled_143.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_amoled_143.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) + +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 + +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_amoled_143.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_amoled_143.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_amoled_143.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_amoled_143.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_amoled_143.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_amoled_143.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_amoled_143.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_amoled_143.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## + +waveshare_esp32_s3_touch_amoled_191.name=Waveshare ESP32-S3-Touch-AMOLED-1.91 +waveshare_esp32_s3_touch_amoled_191.vid.0=0x303a +waveshare_esp32_s3_touch_amoled_191.pid.0=0x824b +waveshare_esp32_s3_touch_amoled_191.upload_port.0.vid=0x303a +waveshare_esp32_s3_touch_amoled_191.upload_port.0.pid=0x824b + +waveshare_esp32_s3_touch_amoled_191.bootloader.tool=esptool_py +waveshare_esp32_s3_touch_amoled_191.bootloader.tool.default=esptool_py + +waveshare_esp32_s3_touch_amoled_191.upload.tool=esptool_py +waveshare_esp32_s3_touch_amoled_191.upload.tool.default=esptool_py +waveshare_esp32_s3_touch_amoled_191.upload.tool.network=esp_ota + +waveshare_esp32_s3_touch_amoled_191.upload.maximum_size=1310720 + +waveshare_esp32_s3_touch_amoled_191.upload.maximum_data_size=327680 +waveshare_esp32_s3_touch_amoled_191.upload.flags= +waveshare_esp32_s3_touch_amoled_191.upload.extra_flags= +waveshare_esp32_s3_touch_amoled_191.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_amoled_191.upload.wait_for_upload_port=false + +waveshare_esp32_s3_touch_amoled_191.serial.disableDTR=false +waveshare_esp32_s3_touch_amoled_191.serial.disableRTS=false + +waveshare_esp32_s3_touch_amoled_191.build.tarch=xtensa +waveshare_esp32_s3_touch_amoled_191.build.bootloader_addr=0x0 +waveshare_esp32_s3_touch_amoled_191.build.target=esp32s3 +waveshare_esp32_s3_touch_amoled_191.build.mcu=esp32s3 +waveshare_esp32_s3_touch_amoled_191.build.core=esp32 +waveshare_esp32_s3_touch_amoled_191.build.variant=waveshare_esp32_s3_touch_amoled_191 +waveshare_esp32_s3_touch_amoled_191.build.board=WAVESHARE_ESP32_S3_TOUCH_AMOLED_191 + +waveshare_esp32_s3_touch_amoled_191.build.usb_mode=1 +waveshare_esp32_s3_touch_amoled_191.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_amoled_191.build.msc_on_boot=0 +waveshare_esp32_s3_touch_amoled_191.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_amoled_191.build.f_cpu=240000000L +waveshare_esp32_s3_touch_amoled_191.build.flash_size=16MB + +waveshare_esp32_s3_touch_amoled_191.build.flash_freq=80m +waveshare_esp32_s3_touch_amoled_191.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_191.build.boot=qio +waveshare_esp32_s3_touch_amoled_191.build.boot_freq=80m +waveshare_esp32_s3_touch_amoled_191.build.partitions=default +waveshare_esp32_s3_touch_amoled_191.build.defines= +waveshare_esp32_s3_touch_amoled_191.build.loop_core= +waveshare_esp32_s3_touch_amoled_191.build.event_core= +waveshare_esp32_s3_touch_amoled_191.build.psram_type=qspi +waveshare_esp32_s3_touch_amoled_191.build.memory_type={build.boot}_{build.psram_type} + +waveshare_esp32_s3_touch_amoled_191.menu.PSRAM.disabled=Disabled +waveshare_esp32_s3_touch_amoled_191.menu.PSRAM.disabled.build.defines= +waveshare_esp32_s3_touch_amoled_191.menu.PSRAM.disabled.build.psram_type=qspi +waveshare_esp32_s3_touch_amoled_191.menu.PSRAM.enabled=Enabled +waveshare_esp32_s3_touch_amoled_191.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM +waveshare_esp32_s3_touch_amoled_191.menu.PSRAM.enabled.build.psram_type=opi + +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio=QIO 80MHz +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio.build.boot_freq=80m +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio.build.flash_freq=80m +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio120=QIO 120MHz +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio120.build.flash_mode=dio +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio120.build.boot=qio +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio120.build.boot_freq=120m +waveshare_esp32_s3_touch_amoled_191.menu.FlashMode.qio120.build.flash_freq=80m + +waveshare_esp32_s3_touch_amoled_191.menu.LoopCore.1=Core 1 +waveshare_esp32_s3_touch_amoled_191.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +waveshare_esp32_s3_touch_amoled_191.menu.LoopCore.0=Core 0 +waveshare_esp32_s3_touch_amoled_191.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_amoled_191.menu.EventsCore.1=Core 1 +waveshare_esp32_s3_touch_amoled_191.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +waveshare_esp32_s3_touch_amoled_191.menu.EventsCore.0=Core 0 +waveshare_esp32_s3_touch_amoled_191.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +waveshare_esp32_s3_touch_amoled_191.menu.USBMode.hwcdc=Hardware CDC and JTAG +waveshare_esp32_s3_touch_amoled_191.menu.USBMode.hwcdc.build.usb_mode=1 +waveshare_esp32_s3_touch_amoled_191.menu.USBMode.default=USB-OTG (TinyUSB) +waveshare_esp32_s3_touch_amoled_191.menu.USBMode.default.build.usb_mode=0 + +waveshare_esp32_s3_touch_amoled_191.menu.CDCOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_191.menu.CDCOnBoot.default.build.cdc_on_boot=0 +waveshare_esp32_s3_touch_amoled_191.menu.CDCOnBoot.cdc=Enabled +waveshare_esp32_s3_touch_amoled_191.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +waveshare_esp32_s3_touch_amoled_191.menu.MSCOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_191.menu.MSCOnBoot.default.build.msc_on_boot=0 +waveshare_esp32_s3_touch_amoled_191.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_amoled_191.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +waveshare_esp32_s3_touch_amoled_191.menu.DFUOnBoot.default=Disabled +waveshare_esp32_s3_touch_amoled_191.menu.DFUOnBoot.default.build.dfu_on_boot=0 +waveshare_esp32_s3_touch_amoled_191.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +waveshare_esp32_s3_touch_amoled_191.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +waveshare_esp32_s3_touch_amoled_191.menu.UploadMode.default=UART0 / Hardware CDC +waveshare_esp32_s3_touch_amoled_191.menu.UploadMode.default.upload.use_1200bps_touch=false +waveshare_esp32_s3_touch_amoled_191.menu.UploadMode.default.upload.wait_for_upload_port=false +waveshare_esp32_s3_touch_amoled_191.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +waveshare_esp32_s3_touch_amoled_191.menu.UploadMode.cdc.upload.use_1200bps_touch=true +waveshare_esp32_s3_touch_amoled_191.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) + +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker_8MB=RainMaker 8MB +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker_8MB.build.partitions=rainmaker_8MB +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.fatflash.build.partitions=ffat +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 + +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.otanofs=OTA no FS (2MB APP with OTA) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.otanofs.build.custom_partitions=partitions_otanofs_4MB +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.otanofs.upload.maximum_size=2031616 +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.all_app=Max APP (4MB APP no OTA) +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.all_app.build.custom_partitions=partitions_all_app_4MB +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.all_app.upload.maximum_size=4128768 + +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.custom=Custom +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_s3_touch_amoled_191.menu.PartitionScheme.custom.upload.maximum_size=16777216 + +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.240=240MHz (WiFi) +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.240.build.f_cpu=240000000L +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.40=40MHz +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.20=20MHz +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.10=10MHz +waveshare_esp32_s3_touch_amoled_191.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.921600=921600 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.115200=115200 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.230400=230400 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_s3_touch_amoled_191.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.none=None +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.error=Error +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.warn=Warn +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.info=Info +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.debug=Debug +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.verbose=Verbose +waveshare_esp32_s3_touch_amoled_191.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_s3_touch_amoled_191.menu.EraseFlash.none=Disabled +waveshare_esp32_s3_touch_amoled_191.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_s3_touch_amoled_191.menu.EraseFlash.all=Enabled +waveshare_esp32_s3_touch_amoled_191.menu.EraseFlash.all.upload.erase_cmd=-e + +############################################################## diff --git a/variants/waveshare_esp32_s3_touch_amoled_143/pins_arduino.h b/variants/waveshare_esp32_s3_touch_amoled_143/pins_arduino.h new file mode 100644 index 00000000000..ed6df1d3a2c --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_amoled_143/pins_arduino.h @@ -0,0 +1,49 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x824A + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-AMOLED-1.43" +#define USB_SERIAL "" + +// display QSPI SPI2 +#define QSPI_CS 9 +#define QSPI_SCK 10 +#define QSPI_D0 11 +#define QSPI_D1 12 +#define QSPI_D2 13 +#define QSPI_D3 14 +#define AMOLED_RESET 21 +#define AMOLED_TE -1 +#define AMOLED_PWR_EN -1 +// Touch I2C +#define TP_SCL 48 +#define TP_SDA 47 +#define TP_RST -1 +#define TP_INT -1 + +// RTC +#define RTC_INT 15 +// Partial voltage measurement method +#define BAT_ADC 4 +// Onboard QMI8658 IMU +#define QMI_INT1 8 + +static const uint8_t SDA = 47; +static const uint8_t SCL = 48; +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +//esp32s3-PSFlash SPI1/SPI0 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_amoled_164/pins_arduino.h b/variants/waveshare_esp32_s3_touch_amoled_164/pins_arduino.h new file mode 100644 index 00000000000..ce17a49972a --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_amoled_164/pins_arduino.h @@ -0,0 +1,55 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x8249 + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-AMOLED-1.64" +#define USB_SERIAL "" + +// display QSPI SPI2 +#define QSPI_CS 9 +#define QSPI_SCK 10 +#define QSPI_D0 11 +#define QSPI_D1 12 +#define QSPI_D2 13 +#define QSPI_D3 14 +#define AMOLED_RESET 21 +#define AMOLED_TE -1 +#define AMOLED_PWR_EN -1 + +// Touch I2C +#define TP_SCL 48 +#define TP_SDA 47 +#define TP_RST -1 +#define TP_INT -1 + +//key +#define KEY_0 0 +//ADC +#define BAT_ADC 4 + +//SD_CARD +#define SD_CS 38 +#define SD_MOSI 39 +#define SD_MISO 40 +#define SD_SCLK 41 + +static const uint8_t SDA = 47; +static const uint8_t SCL = 48; + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +//esp32s3-PSFlash SPI1/SPI0 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_s3_touch_amoled_191/pins_arduino.h b/variants/waveshare_esp32_s3_touch_amoled_191/pins_arduino.h new file mode 100644 index 00000000000..7e882a7ef46 --- /dev/null +++ b/variants/waveshare_esp32_s3_touch_amoled_191/pins_arduino.h @@ -0,0 +1,57 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// BN: ESP32 Family Device +#define USB_VID 0x303a +#define USB_PID 0x824B + +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-AMOLED-1.91" +#define USB_SERIAL "" + +// display QSPI SPI2 +#define QSPI_CS 6 +#define QSPI_SCK 47 +#define QSPI_D0 18 +#define QSPI_D1 7 +#define QSPI_D2 48 +#define QSPI_D3 5 +#define AMOLED_RESET 17 +#define AMOLED_TE -1 +#define AMOLED_PWR_EN -1 +// Touch I2C +#define TP_SCL 39 +#define TP_SDA 40 +#define TP_RST -1 +#define TP_INT -1 + +// Partial voltage measurement method +#define BAT_ADC 1 +// Onboard QMI8658 IMU +#define QMI_INT1 45 +#define QMI_INT1 46 + +//SD +#define SD_CS 9 +#define SD_MISO 8 +#define SD_MOSI 42 +#define SD_CLK 47 + +//i2c + +static const uint8_t SDA = 40; +static const uint8_t SCL = 39; + +// UART0 pins +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +//esp32s3-PSFlash SPI1/SPI0 +static const uint8_t SS = 34; // FSPICS0 +static const uint8_t MOSI = 35; // FSPID +static const uint8_t MISO = 37; // FSPIQ +static const uint8_t SCK = 36; // FSPICLK +#endif /* Pins_Arduino_h */ From 870468bb25a4a64879ee5e472bbfa2ff65c06735 Mon Sep 17 00:00:00 2001 From: ASDosjani <62965528+ASDosjani@users.noreply.github.com> Date: Mon, 4 Nov 2024 22:43:07 +0100 Subject: [PATCH 117/406] Update BLE5_periodic_advertising.ino (#10538) --- .../BLE5_periodic_advertising/BLE5_periodic_advertising.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino b/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino index 796f63666db..0b9d4f87630 100644 --- a/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino +++ b/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino @@ -1,5 +1,5 @@ /* - Simple BLE5 multi advertising example on esp32 C3/S3 + Simple BLE5 periodic advertising example on esp32 C3/S3 only ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED can be used for periodic advertising author: chegewara From 11f3cff53f097b3e3a901c7e5f21e49b9bce828e Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:49:40 -0300 Subject: [PATCH 118/406] fix(get.py): Check if win32 tools also exist when running on win64 (#10565) * fix(get.py): Check if win32 tools also exist when running on win64 * change(tools): Push generated binaries to PR --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- tools/get.exe | Bin 6930008 -> 7493192 bytes tools/get.py | 12 ++++++++++++ 2 files changed, 12 insertions(+) diff --git a/tools/get.exe b/tools/get.exe index 161cb193cae89e3dbc84006a7c7332e2683eb329..671b1507b0be78379e80de0100fce5af0621c75a 100644 GIT binary patch delta 1572460 zcmeFaiC>Ie+&_L@Gi}<@q*6>NiXs(Cp_Pd?BspVL7c$`)NOu(_|7KAw`KYuEw_% zN$$xjm_z37^eU#-ycfNZv9vIwy%-ORrdGVpAW0;)$boPToK)LN4kn=BbdQFSdm_zCLrLt$(hHxD5mvbOf;^%};=tRv{NOp~=WJ&oyL z6KgqNlcEA7nQ^47(#=++dXnpb871+$B5A0#qx=AK%%;mo`;=lKf~fcoUMc;k1PkY@ z3c-fWJj(et3T%c9yb38pic$y`LdnT&bYjX%QVf_K3F@^0wRT~XLLrg{SUV~N!);{lIW1; zNJK0pA)XNIp_jLE{;S+Vlx+xE8fGYW>&XTXdAJX~iPmFw1o;{G@GEz%PgM1v@0<2HYL)J)}M3P5OYzMImn~pP33*xvIR6GiJX6>PXCdI< z8q6I0w+3ra8IpO^H)5b(H{~Zj6X7Pxe415pW!}oR87KQqnO{ zw`?ssX`p}+dh zw37z|1z3m3o6u|+%<%>y$$d0zBGb1^xH#efVy}CH*lEO)8IKa$)-B-plb(~xR-psO zj}%S1BFZwqEJBw+|8T2D2>P{gfYjGIgeawYJxDP^kWgJvpajGULacZ~dd%E^d4Ysy zOL!ffOX_-bB7-Fa@ij<6T0*Z<93lz|ib7%{ktEwX#1kcSE|U*phS+!4_uIy!PLiP~ zl01-~W>(m@rk60g?5FCV-uh2~Gh^o9Mh{~`9h`KG(^Xd7$gFTM6L)84olt8bSKsYU zH06919emX}$vKi=IQkFC?`jG#^5ISZF1Kk z^dY9AtEn2(ou*`GQ|LA_g(pv)Y0<5*F-Gq^=1K~%b#jA?3%9_kzBFU^)9?A@K z3=IjopiuZvIxopy{A4uf)JEutFg)U_LnZb~xujQ8q|Ug{>hIzxn?Mnlr0HQK}$z4Xj2z zV6Omanh+5Jxbl}V-JMM7mCPWgw!PP^{wG~Wa7enfQEZ=AANk)zJew04%WQSBcesSg zTt#73XbGA4hyMq2;Ll-xI@!{v7%OKRfwYMf5A#BRh^W*+g$iI~uk0 zwRS}1)RYe_eB9aFRK?H+N zflfY-+2Ueh8F%(?N6ewvhT6>$Nu|RT0wMFn#k&82Mm}}L*E)_=LLqp+lA9}q&HZX3 zA{p5ES_=*A*k$_~C_k#&mWU+T)@-^MuVKu99=$EvEMa>=tCwj1L+}BLaDk9Q{AJ@NH5S(CgB)XiD?KFxu=SpJc}K>NWl5F z{A7Pv217XutwlB@O7f0owJT9CXO~kc6VlU`PG{!!w4`~=hMuEZ{5Vb4##JeyOjFPP z4#qwdZa&^%ec8UzYbLeED%y!q=U9U8dJ{nk!@uLttT=w5FAM%s5jcUxFWPIEtUG@Ks zV)?(K$PnBdg=QKNW!R5@a*34wHJB9ezY;O z+{0M=#|Bd0pjPsB%n^?e?L#VWI@6+0JMGmf?--_gAEN+D*n;iHf+4D4FDAQ>tA#zLx-1{VI$ed2R-NV*A2l)rF$?)i z%H{UV^FEfXKDVYR|4BDbYLS2}AEEp?W7IcTd&+uciNl$gzCE-%tGt%X!MvtB2Zf+M4d)Z7-a0TO6#-K9t%NGodjOC} z-&5^o(k==|Ux3YCunApP2%aMv61rW_C1juw?BNnB0i!M-)GI3Li8L|GJ<`lwz;SmG z?ox2`R9p#{Y_^ixN+B4`QCEUdJBBPWQo$M(do0I}Xl8fd*zttjm1C!@isg&*9j%Dt02r-rLOX!?868Tg0)oRcwEby{MTjHsI)TY(r|z zIQmzzB_UR6%hAU))1RlZR=G{s@7S}G;HirJ9$~0w&t~>qb~4A-XlDCx?04AV)dq3w2FPr426OD{_kV3DNWu8S5Wh$0 zLXQ4IMYrVWC!6Ut9J_?DKmTUyS*But;YRYRW_A(B-cQ&UId-v%eTieoz8C*3i-em0ibY_SMy4W`5u z9DO^XZ{+B^RrF09eRp%>lQ?!dVaIap92I*8$4+Tx_u$yEgzd?(=c(9YFOEK{nXbvv zM-X}|jvlR|x8~R`&FlvYSgQ;q>{kt}Rl-#4*9e1E^qbiSIJOI6pCIg^Qh}$6Uck}i zZ~q!GnWMKO^d(&4Rw{ND$3EZ84(8YtV8aj@5T$z7*g!bn zRtPqdek@TJaN5mEZ6>E}gUF(^i?$+#O+1q&@)=VF1$xRzOgz{Ki~=YG=7fvZYlBon zppg%{+Po)l9D9Kra6J(=hRjx3@zx^tCPh7&q@A?@r#0wCC}O)*Yn!*$6e z4K4~L>g94${1v1Vl0#j+JX4FN0yDlR7>T6ATOrjC=-2Y2r3!`fBXUQmz6=pW(%@G9 zml7^NmA&eb z>a{{53PB@jM@a*!iE_+%LyA#LR2hl{OVsll5|o=DC(}L>^-#ozE}88E_Z5PJAQFp} zBdU;%x*nR0NAb3pRfZFmRIh?0aN#nue4q)#4C<=$XbK9&9_}VEWrIx2UXkTY^7Eu8 zyV1lcAV9jzo}ANynWjPJZLC%xy2WK>%hrAd3)P&=bPur87(&9HFyR6I8a_l^#vBRg zW%V6*hzdbcBDZVA2^D;A1fwizg!TO@qZQbJp2^q;4imQ}niCgsX}1}>W^zMmiu*rY zw6z4iBMDqb0#n(*a=9+KRbwym5(uFWAtVt(I7?7}_YwvoOL~WSq*iFR>+&l3-voyd zzKHO#WhdccLP)~pr7}mBU`q&w9D#(3noBg6B%npY>xsFz3{0BCr;u#hebZwcUy;lViQ7LZCO79qlf#43Ff}2f2{z4fC8^*D zdIpZ%814)Fmb6N_42?9kpt7Wk#Hv|PE z2!}FO&2l^b<-TKDhPa5IkusA5#$oh`%RY|qsHZ`v5Nv`%ls4ZJ(}9mG+Eb#wgVkpc zeU^_WGIvGa>CY#YR15<`qb0ixjE z98o+CR$WmDIyT4n4J-c>Bc015fsH`&K!nRWKNNy5bGS@kwQvL?${AuZWRis_UhKWD zf$ujz@=4{2l8d5e^C>eza^TYSM%3nlZ)L^~ZX>oukV3GCjYB5BhUdgT3;x;+whOBF zWi{c@NE$F*S(3_v_>oon|BZN-^}Dftme9m1Y@yJ>>@vtTVFhBPLWxQo!v&MCoXC=i4XUb%4Ti9O_1W->LeYXt z$W|e^&oWpu-g!m}a~X<&tl2O;nWp8e?iiO$B|KaKw{eOWoB{>R;S@!G8IEF3lf))4 zi}M`kf`tmf1WvJ(Q=l9n%%P!y;_YK$e0IvV-HN=FchZJz|BE18$pe3hztCUuQzZGU z5LC`47YClCe@X?va!6fE<;!^NJ;xN0B$(Ku8(V;VUi__&BU8-ozaI`u+sOk`U-lCt4Cv6?v(+GW%# zB;}7HPLc;mKKn}oY8w;+icO_do>WEVUW4>iq_h(CeV|Hp-^0W15j@cnvvAXh^EdX% zdTrStVk#@3un zzL?52S@}9PJi^hnzkY+n-f56aJx}&(_GAud+!S3&g1H6ALcSXwjPkSW-JD)JrWJ{y z{OTEEzYAO%WDjH_BEuqVI5Q?pSI1>E;FhTC|TW@E;m4O123 z6tAc|1A8SCRX9-*1J><_>X!tnz`rUPx%!jp9VFUbjK&Bz!`BbdpVH3Rk{z2XCT%8o zgr(PGqLdD|W$$Z)(NX8mU^~H1Rv(OxI*n88;1t3-e9KkO{2Lm;933GT83sSudUoZw z<4LfjTp?)3`GYw+78yNG(U((T4o7r-sg(NWRCKp;weh*P{_6`-&-DE%9}ESks69PNWId-CBs2B7Y)aU=c_N(McKzZyE>kwv zV3;^<|~bUTjz7Oh_Uo4afL4w3HtJsg`;0n(H|fXCK=UC-@?)NlEi0n>^v3w z0LOM|X3ylKmKsMI7CV&?OwbtBQV!(6iL%G_xffTbHoM za%>Y7TgI_Nn%QGH_V;wKyK!t@hU!K=ilcXKrg!7$)r3xS^mmZi)_3RFYRzn#V_zfe zO73Rzri!h{v7c7_wPEE1)+z_V5ZCVF=(#HTGX$cZh0XL`9DNx{JdtCsRI!h8?3K;z zM2;Ot*!~=Qfr_2Rv7?*WVtWsFpl28nckLTdl2?}?yga!Vt3-$!e;jS zaJHTu3HvO^c2co_A`I0O|0@4$ma`n)kkD6fbR!l0I!C|L%wEBq6Lt@dT}{~Rjrt6ZzNDGngQFJ{x+X_IuS(pDV^3^mYjW(Zg#7^P09i^@ z?A9FHqnZ6+JZqIjgndBF(KA)_*9e4JjGO5PIQnElPv+Q>EE~&M0mrVt`PYWY9J@bZ z2Xkz16+4S#Uu$LukJn(!B4jM4xQrbXpxW)-T80FmQs0J=J1q`;)9t;46CVIfaE6GzYDRQ zKS{RX^4n4_1lLg$fml|H<*g4j#9F7!qq>2I`W=NC+9&@Hd2}Ug+P4Z9BPzWxKA_bIqVwZE0&=i892qVU+ zEXIXn$v=y`jgX39Yd==!h#w`8j6HG%NeAY?;a>Rr2^6*x(Tx9!0{__mVQz`jXQF zYxNz>{%JPiGYHF~S&c$ajo5fFCvNLYPJ86khD|?-+=+{fB$bi7;_Gm26}+k^S0FoI zl^|mlV~AfK$q({%M4?}ryE6; z?m{H?eFu3|r4Sg7L}RdBL>kPKk5WZ1NjMG`+4_7O!8S`Tg&-eNp916--&rBp3lF(V zk*aH;EO?`b2c@J?wg%jAv<xaYG>g!-%97fu3UP73}*P0CZAV~#xCM{t4#&+zH!xH1$q}9>! z>S@2*C15lgkm8Myr}iUNEte;}B#8GmqO_lic=XIrW?gI-ohomYdB!p2u|j$ZQy*(% zI{-Jy@;7X=lU`T#g7muhcCd3F5+dJ$2QHWyN|-(~OouH)=5ibKB40@ClxY7p+sqC$cc%HpTutc^~TL7A2{UCbSd(^Al?~T=i4YLdZqjt zllk|>K0E*6F=m{Rpcis!9z83>tio8#>ZTJyx(u7=J!beU zE5RhhD5fbAO^+=9t zC#Wdy1hpR^k706Vx53NOy|X*Fc{`LxMQ~I3VsJ&0VTS0Gc}(r>zTQ%ViL%m0kWL2* zPHkO4sna2|4cciO36>a~oQzT_1i1*pNLygg-V;MlK_>G*!Aw-VRevw=aJlG=qkjqx zV?z*&mAbR>88&$+aP}p))Mz1`4%sN;8_mhPFt_5(x|y<>7^Dw|c}W-o{9GZgL4% z2+jqu<-;c*R*;C0szNXw9!yl>B8fCdh_axcYcZ?mSklXwf;o1Ujp~>ZZhIB7FQUj7 zKMekqK#~wUH2*wg=*0G7atUQJoV<>de8RmEn?6|_;{(aM;t0c&D464LMT5Sp5IA!U zX6HV}+BKnr^CPm$z^=}NGiIwIu31+jmf}L%Z}kPwxTRbYk1v(%q5JPkJ|c9-{ogRJ z&_eQBTmH!nwO~g?;)1`62wAzE-{WS4T=6LceoRQB5wIA28X8?Ri&wFozN? zcq`SIvczd-zCFnPCB7qhrYc=!O_o4nen)u^CM3zv_BHqGh)(DRr^sMa2rL5F9w^93 z`z=hyUd=#(8x$?(Op=Z1daTj`68wAwWgwFVDGM>P74tjET6|~_F{biTGXzxUtF=)$ zb^Wa%v7i<)u;Fm-8Tj>HstOLC_qT$cC?U7XlzmYsirS-4Wa>N%5AHImXOm1CNEJM} z2kfYv8J^yYn5T0!2b3c?z`*aiTwjJcyEXI}hM!f+pKI8aT2hZ^#sk@wR|vjANNpku z@d884G;hF_Z)5D|nHi;UKLL4u(ga1|N;H}oHP43k#FFeb)Y2QFau{|YcdK-zD^*_{m9r=UF4 z@oMP^0eN=c3eir3lAeQtJSvvHc7JB*PMMQ63;k5c{E5 zWsNQHliUc%8g?Z>@+%-K;fUm?AFiIWhMmm{T<(R3{rnQlphAPRMC9tFI2YlY6|G** z%-w56mopppn%kEr1WUc?2w%5ozw!hx$$6#JUFxk+ibAP(6DKmS_Kt02om7;PocH6G7!(BfmHT!% zXRxHV8hY>fv|k2u-uPigYL%fdNbd-pSK3e7Aj2GzNaAG_CEvXyR|2FxJV>}S zSb?{+wg%~^!Sll@4+((9^UX?LOcJu@(q+^1l{6rI8OvvH_C;CZge}hBvl13#U|O>~ zCKaI%<}k`2Gasq4-&q1AT%AM`uBC9JZ9sh0zU0FkFMDm-U@RANtptsxBsbN|adZj8tkz!)DB-GlvuAd|@ zjf;sWUXr_{aIhe2B*_CLZ-i{wVza3r3Y(G^Nl9`)A_s*$!hAh2AHST7J2<#sd4idr z`z?d?hloXj&?n9s6zC52H7GC=`AYoK{M;)HGSyKmT#MRvc;^1pApJ)Zu9P$02TQH< z82XTjVMjm7d9prxNlFb0LIcYg+e4O4zWfG>-*WPMzZS|0)aj-*@DlXkW9_)Ol-xi` z0t-Y^qfN*iAGr?M`uij83`M+A1X{#OQhpg@-V=+M&?`$Vn~)_5X=rKDxoVz>rcu}{ zS&le)jYm@4!JOQg$!#$jkH0&#k5)tfe!#3d;zi$P9vv~KA02NvVoe*pXgzx%;tH+K z_dcKC=_R@DCAo0i@#rQ#&tMBvo;OHvelt?p_6Tc^YZN4B@}I*@w|rCVwfytF=pn}? z`J*)GAIIOEdfS#hop$Sf!L9prx2NKY&uA(9JE_FoN_?wCHW2^0hxgp%-$faitP>D)EF8FDkJ@iE<@2 z5=8!#k0Z(2um~ zGNt065=)i%REZ5rv{EM6Q;EJx43)VR^4g0pD!mm-e5%BEO8l-wjc;6eOq6J^#DPj2 zp~OffE>+@oB_3Adc_rTFP)xm0Dn2N&QHia-a~WDI(NT%sN*toZ2qi91Vzv_3DsiV0 zk14T4iPu;pT}i2Ur$jYn3z;a97@Pc?gU7ez-$Z5K?yp2ACAL!{Pl;cZ{8vi6t;7-~ z9wtbpQSuy_{9CHTNZF?%-aETEd_ksi$$vb_wMq4O{HLD$hYE+QCjSv8;6GanG*0o> z$I@{H+wAxTG*A9mcC0hMr=9B)J|#pr`G=W`vQlSE$&x02%wvF1GCh~55Wrxckx$g^l-JpuW6DdPl%s@-)G^KAK4gie(NNXsuA8A zdJtU{;aEEnU5G68AiuRB5<&R!nJNg|V2X;A?K{XHt$l~28b@Ntp8N3!7K}K=H&hom z;`(t7oT!XXS%S>^Wy#0*ZQXJPP}EMibP}Y_qtrt+SbrgO*-API|JTpPk=;7Re`b># zil3|xqo`FkNXl9i^$JJocpQHxv4&7Ha zIv4)0pN%8yk;gwEAZ^tZwz_zes{`woeaqvI?o&UTqTJ&t%C#Ip+G><`ye{gY!|Db@ zFCuzWn{fX1v+-ooe14j2#0kD|N^TlOwM<8aD!>=0QG$3wEv?B0T0}P$&X(x4c$C(w z7Fxug2IoO^Nc+G3{}Bh_f76ydIl*sl>Np3RcDS|5=zsk(K>^>oE2+d}ElS%-BaStd ziw5P0!VQG0SH)=d%X$^?6XCFj+_$=26rj z?60Cp3dATEO<4c56BM;XnJNkY*Z)7_kRFUU)PK{Wc$D7%P!_Z-;!kbe(iKlOiKT@& z*v`YY#I+!+jDLh~CC4*Qq7TXBQ3v4UH3b82@~6@K+*-a2@4N&Wr5IlIwX(i@`NlGN zIp4QOJs!KO{w>5zv!s$o<&Z(8{I~WqAC1kU*ny_hS;;0;@Z102uHpZ74ga@mP%iTS zKioAG%)G;2t|P1WTWE@bp9}eD-4S^ToJRs+IVs3`3LgW(QBrohApico_@WyTh`U+sW5B5AH zV_(Qv)YV8_plSo~??O)&{3ip%2tWCngVACjHdfFR3=67FpAoU0uk&BcN(&%7((7~m=~TBVCYCJ7?8t( zk=WLyKqh;_i^mj`J{lD9_sp-vI zyZ&U4r;~w>2NJ*mfoIg)9Ub%U}c| z1M`lc43JBXP_mcb_$|d`$47R0@8EPH6D&VQQPz+NK7#XwTo0u4P;tor?%V#|(~-TM zZvloaI0OUWav>9pf-8Yc@JSI01Q{4a)xaZ%hv0iSLL!^XK5(QNaW_tFfNO+47kCp+ zs}j}(u0Ml9L(T;@!3kyOzVq93cZAC5ET$+pk_5p^#1DNbuty1u4A~X956)NC;s?JQ z9U^o4!FQ)O$`S}%lpX!SZ$nqeuEM9Mc85L3&B@eGI7dnhze^A+j}Sqqr(28#jYBw&6G1}XT3z>l@C zlWgoSRLou`{l#x%T8;ePeW0jCAGvuZ9XPX|oE6XfLVc2C&%x@GjkJVcU|YCS$QyxP zUoqE1_5~h*I|%t8(Dxe}o9Ka$i7e~!o8Q64{63#r)j&~4;m9nU2ORkmeGJqwz#nif zvgF^$jg+?RH)`6*r9^NCTso523AFmdjR$LB3ETqc3Eom*%*bvb3B3_`s$59X)HgU6 z**6qGycQ}?b(+f8rKtrZ73nZCYCf6f)~&PU94#8G~}&7 zhYmEQ1=$f;tdvWDVV$_lMgXfiD+>hNrPX4{b;HI zvOVyl4^72Gt_OySAj`)7fvG&8+Bt}(bb@GVuPhZRdaZ2TAO6r`)d(rYF)${Srp#fn zIH1Qc6aW?=Xd1@J=0MNkhz&i#$s;(KVE!nYDulie*m5jnnO76~bhvDF6TibS($d0- zG&LWN%!bv#v6H|;Zd-wxlWD31vKBCP3Rl&1U{wT7y@H-#N+eBvg-o!06pfLnr{H(! zei5piXqvK#r70nvx!VFi!C6D5X3*68nKVVZL_KinTyzQ91O>lapAZB`CesveAI)p{>5ag{i%@t_bAfHs zVE;#a${ZM-j>>{h@CtsOAiGk(n$UcyuYU z2S0Bqy?TU*Gz&X%W0|gJ$`Ju5q%MB^E=?O&B#|a6EWz6vMjK=lVKIPou<-u&{QK5Ne5nntA|_)+`SXS z2{&zfffIMZ3bH4(n!A4$f=BE|FdQ*PF7Oi^iS`xfzK3Qv1RlV6xD+Hou-{&q3Ww|o zRNsgGE1SSm>palvmvHZpgzi!F0Jv8&H@@0XtT9r)n!D**47Y=Mun`>D&k!7X z0;$QK^I<1f*-yS2rZMEPvyi5y6d`TMkwEGs*Fy;2fFrRhfF1G8`!qPdz;35$>M>+T z;4C;Y+~R@9;VAs{C=d7vE*kPzpc{UVXARi{xB*TCdE*(nJrz|9>ms2zU=AEPP!P;G zi=sc3om5jBC$0zC=n_pmyn=AZkAc5R!H3)k^uK}Tha3PreiNMsT_g{9yByPBH6PnH zno6$Vx_S!G>=su+YhbZbE(PY_h9SW(1eR2CofD`*{f5Uywn<&B&4fG>UWGq0^?=3` zG|ctDyAL_J3MhJvJn?%ug4J+j_!9i{gr=5&Pd%k6jpt|v$XY-JoIUu|3!3^3=P46t zs12Y)Wn%&2tq2+Ofu=@$L~O_e-9EvrkUfAcKch(?8v&<%;krgNu=p$bDfA`4d*8SL zSp_`PKvU$$gC)SYUnn(X7Js7^Fl4AkOkaO6WT4;qhn98FRI|YL!b=kakK~iW<5Bf+ zq)QNd%;!<3WyzXqZTwB}L&-Qb9(5Fs^oBfO1TI~L&_@Dy!TCbo3tX>8 zqe37Ptbp@`Oz;OBnT{KP_smdi=&OK^?eKRYAro9>$zvAbw9LZp~wtK!R7{$nS;AfY0Da2Gzj3Hn?OY835xt^4NKg;M7hiw9KsqJJpPBq1GnG z^%Yvdjz>jz<}92JoY@tA=;MLEx^YEPbL3ICyQBKAF+6~Soj6m45`-hC9)guFC@JFJ z0s8bpNg?|J8{u+g&yllU4pbiQJZhi^8e7&;_fFxgCPwQh8zY#Tys zvJqk;LapK6K_<8iE{{x+Ks!8(IVdyLL5&P$eRR~?bSLZ6-wRk=$dZfLs3B++$OKQr zO@>Tx;1nKZBFiALt7Q9h)Vhfq5aKc&>Biu`71p!|>c#S?JJ1^fm&Wm^SCF%TMzeU- zMaTp#@v5iXc~_S zP3K_;&S&vU29GL}Jx8z&xtJyw(w<9sIPvgV90%DNayW2>6orvl=wW#v<05=Hk6Hjn z3Qn+h4v!imo2jSPA%?87CM#eAI5I38SMsPwGW0&AME(}hwY7)}nf$qmk?T<{$nOYl zz;H!ef^9bO*qwk0@Gcygz^Z_wx50+sj{&}hyCb9Z)!K*)p)%aXqY~g=K~4fX?dH0% z3vl!vbQ$PVfc0>?dxBU;D)C#m(sb6?0&S^V*j>)gon(%h!`irgn z1_uu8((1=)H>cgMC;5}y z=fp%!zZ}$g@UCmiEcRTR^1H+9&4{a#ObO%j=1+6K)p$=xMfmMNhj2<1MF~ zdHzV=IRC@kEwg{0-PONom-zX|NA+zy(sTwL+O_ub*US^UZ|y1GUAgCIM8%$>h}%== zIRtK5m!Ey$?(uKt<5SB$#!t|2?&p6@v{+`Q=ZRWS{rmL@MF-&UH2lYf7@R_ z>hXBX>~FtPpUjmf#|4ib9iEZzQ=hydFy?LJ^2ZrZE*vb}^Qqs&%DDEU`wqC@;e+`6 z=F1V^zvl0VUUTD|Yq_}7CH>r=!9$`K4jAvQaaRABdP6>Sc3jH%#Z^{~qteG;c`)I- z`PZZs783?MublYnOla-Tr>oCz+K_m2jO+ZTvqqJj|JY`{`_#ENPL%t|G{bJxgh_w* zDVXB+e$Ishy|>jAESmLP=i{T<{qA?zVR~@D`Y&^r)=bEqy5~dujDkfK zQ7&VeCR|9|`f2g|!}q^Fc<^P8?#!Ym(%Y7a`#(suG|n@(-?;Qu-!iFUn)WD0P6=;^ zMLBIgH>hv1QT-yZ&*|(#31;z;E<0`Ced*cv?6Mt}yLPUB*z@q{XFYzUq@FA~^drBx zct=dzZR3JFJjwmK=huk`y%L@O7&X$DEK=9ZH!E2=b90)VwsGUB=V8fjMy-yOYZxa! zdaU<2OrC%5P|3&o{nKwvdhGon)8gr|^LqESz4aZg-TUqEu|@dhs1Xk0!~@UstNr&# z<;PB!yjAOZ+~Zd2bNi}{H>W>TcQ`xcO!A(#u?>fY^LI)zAEmF$(zZX_@y*QjhlkbW z?N6$VN}BM)OfR=(=KJc0pFf{$6C2<8_5NpLVk<@0hy5HG)v)@t&g%o$yNsJMGI|2P z_<`V=0X=U|%&FiBLnnk(-IIlN9a}7(7xDV`>Mkz52Yi*~MXo8@Hd-&Hz$Rt8PL$w;EdRd@(pGEF?a0P11(}ol;-8ta(`W=~9S+)Z)f1@AsC5jnnsi-1TAi z!ZvdAerJ!^7EeBZ=Y4Fseo@^+y|X7xU%z~IYx~&RB)$HVhgPb0Bt301L<7XLv6!dLP~I_=fjW&)nHuylL)&KcB`tn`{@+Nc{>-8aE-L zAKxLn!@m1ND~#9m)Uy&F3ds9;Ns%cYynmG>;LWfLrId$nlwr&b;XqB{pbL>f*N)8A zUNQL7P0i`w-~aCQEdOKUPXZOwNiPdn&aCxi#?ujz!##Frs2kPcNWi z-n!5Bo*HBPv8rTl%-M{!>c;XDS*6>f^DnqP9=*Xd*17YyW#?X7TK#leDV}E%r29D*MM9B4)oU>9jYjJm+@hy@)48y={HwXeCM(5}RsKIO~K)$r!0S}ZR2dFLmNI9FrkelF;I&4ll*=9~82GU-|Pk&>F0-#fdj zZy7K$Yg7M(>%~{sRDUtquy|9~0h%A;&y3z_K4Z|gmmYU^T@14AVz_Zg#`$rHX0Zpy z9U9u>i29fQHWFRu>Hsd7xxS$lqwU895H z%P_fkbj*i>u}|frj^61&pV40>2wrw7W>fExbuMNN-zK-Xyy$SlBi^jzOXlre9l|f5 ztbXiETPeQ!kT-a<+V%Z~d(+#cHg$dU@#*R0nnUw{v~#$%bJj`bM(m?~vAyeJO+ReR zJJA@FX7l{ZfDIJ~hjg&?T-oE=J@=+HI>#ceexByz80{uL=cso5#$kgqMdk?)GG9Ay zIrXk(xJQxsk^W2{v%JKf_n!<{bHQY9aUB0^hZ~gVZMBA%gR}14e>ioDL!0@(e7fxP z57OrkTb9~+dA9R}T9=ZXhRU6X{9epx*;Ux!`Sp+5JN<^;7xpx*YvDWXVBgB1K9vK* zC%=w4^)PNx$%!2s1GkHL#k*q0RMw1|tP#7TXXo?VEX>-Tu+S~r{Pb4${oM{k4C_O0 zUl$tKer38wb>0^FmQ;G@u6dG3lSOtrFC?F=yx)G2x0Bc07~=-MLw=0s0rjM5U!_}i z`W{*CWqd|s>GVep>MwuqGZ^A9c7ONT`H4Nx&AxB{G%7!*XB6LNOH4ykNAXdUr>7&n zZEpY8D>yAEUwgFNX-tj$!uppz#>~0VxpuN{|DPLz55%^;(XL`!|NNG|9haF;xwv4( zn`IMSmY2tvziY95$};;~rh%Q3*WL5n^&;ovJHAPmf14Sw=x~6u#hB%%wu|px2|w7X<+n8-g=T+(Op?MQw?D5bD0fM* zXzPErWMVtb(PcGHHjnEnb6W91vvG9c2m8df>Fdw)_uQH}W7dZ+kpm9~H`-GB=bCIy zw_A57%E5rCa`AW3`!iu_r>?iUh$k&Nb5zv(VC$3LLmrLyepP0;IiX_g?1$YgzRI4u z_ejm|B-VG#{Jhco=kgUFQ=UZ&M;0zRG^|(Rxzp4npN}_I^f|J4WR(`b=L@4~U;Umh zmaRFjn6Ozq{Df_|WKGl2$7*I%vR(9zB1Jy&NpOInMjbPfDzJc886)rQrQezaIwmePb*}UCv8v z?AWy6T=D!bPv>_rh<%#-@oeIiaYa9?-z-gj`Tfa;8PCKYVTR5pM&_O=iS0eCUv6se zl9cG9nQcdYAKm50jHhFh>zdwc_Ue?d%xPQ*U;m}t(@#^Y-Gnl&3(ih;#rIzvc`>v@ z+#}CUvPq7q-n_G)E{dlt@{SGIYG^oh+;yFp-$NgtnRI*eRTDp-PB)$NP5a0+hPJhD zyEP|kQIM{qZ|ls)4(nY5U5;+>W|*=-i@+fZTOA2-*R`KxGN;9ZrKW|W&$Mfi*r@rY zo3L-_`k_&g+qNto_NCRkh+X=R2JP3#%kVUGi)?4Rb>Q&GZkCHnC{rgJ@tt&Et?|`E z!p=?YoHFgjw#5s|hUd8Io{wEMG{twQWof_BDZQ3Hy3qZL?i@Y$KaZ;9y{3NE6&4Qv z)#`HF5AHiZ<$U?9eLYyT=_`HRz4sQM$GpDZVx$c|I$5m~T^t{r?Xrm~93RZrJae-w z=KZJZ$qt204O2qAlKLG_d(3aQa?L#Pre6akBz+$m3w>Qbh|b3a~&QIe|0%x)rs*6#V z-dLRwM|YXgWSslZVNvwe{qf#WNh$T2?Z!&71?zikUR9lT$UAjWiscyk=IfrP6OP;# zPCvY8(C{v@h%Qa@ugqN}X)}4Bq0i;%o^?!Tv-jurFORSfuiokC+R0nD|CUZK44$u< z5mRJdnvO`Jy?wTj8M~ zChpwei@q83llopOeu@_EIKAq8T#QDJzur5uu3eoxG#0gPt}SCb}g%ouQazgY*~ZFBu0TKDvfJ=Lepw+r1Id1BGZ>z^2t z^%uvV($Kj6y_7ezc+=#Q1>W`BA6YlX^=_HLJL2zDrS)vzAIKzTS~`C(*Ih_uqA{NyBX;)pK0~&-{?KSUTf$&BdH~ z(WA6((&DRC8soJaY|6*C__To*FRfqQ_fm15k@}CongoZd&S916F5Qnh7kX7+usU=~ zckj%!jl++8yBL*}eW%S{%F)BNLHox3-0?=8J6`vG@Bd)l_{Wl|S!so@&yDDrU=XzW z;>J&WuMLMy`gq<|t0-N;*Y()3S#7I@drR71W6iqpmy-Go8T_E8?s}Uw6DEGB{~#2v z8S_+YgH)!`Z_~j1#;&?lds)=U(q2c2CmR*SY%YeO@$E*JE%C;?{%1CaC_Qpmuu&D7jH87@{QMf>YoMuu0-_hQE)uk z_+k6EH4`!u#gTU|EsPCrn>}Rx?523DD1ApNz>`r&}2a~qBNIh>x|vhu{sK1;Pfwz7DV zmZkBW-_&)S?(>D$8|?e1J=ELt_VcjQVxzAogkGZ^C4o%_Z`SRws*S98U6^>^}AN8TP@Hm?4f+5@SMV)Uwl8AG1d zy6p&0X&G&wGGx5k>?At$cXq6q+xxFa;>uJqj9UOeUDy#1Lcj*rtc9ee-LktNS;p8V|Q zUpKP!MCPdvp{E$Xjivn;WaXS16t6R8#-@I)=RDM#WgnasJIMI3?xgK|KNh*W99iJ| zS=0CB%Vk~840$|hklEEw-_wdDhr7G(ncStpxW8>_$X2|j^3{E_Rd+M;YW{2? zhzcBRKhH^Pmd(nVv+>Uhru%%+pLcux(ayruIrzVI>FshFRs2@1es6xuxYlo4XZFil zw=F7o?vxaDpH~(iE+00nTCw-ly#YqycH4}7Q++m^^4^l-c&M|ursQNuaiQ9fV=aON zS+8_n&#t-d(`WcOU&WGxvyZBM(3?2i+bj=%TxHLa_rA;P);pE$)-hWA@l3A4hNa&p z(a+a*t7*Mp-?8$w6F>fWp!J1LPJL;5vUTUqE3XAsFV&q|Tf)1N6mIFQxxG!n;6dJV z21XU#F5mJ;KK(+R|H}o2;f7+@Rqc5tg+YVQq!O^)ob<+wbtw7fNGHlKLoq)VASztHukqKk+sDSa&=#Eb_{AtA&=I+AMe2zjoCCr!0E+VsY>7 zm3E)!KX@v6Iojp%oK=lCCa*klsj*KF!ycldA~i&$7vP6 z3hQEdWr^0tLjSFwKk4pjpP03JZAhmMk*goox`=a6?vV^JucX^0Mfb^bo;fCcVo8Bx zp`-UM%XS@0%aXM}_Zo35GiUyOm)vXa^t$h!Q`)WnJiga!YoSF&VEIWux1gxAv&)mM zuHD>QqC2I*`Mp}lAt7xa&e@mpZ19$eVWu%X_B(X98yj-^5#2R%>E!l5uih#fUA-iy z%&=FVb!)cm74NoKr`5XY@*-1{v7(K(9fs;VOgpsIv~}++^&T#($K05*ch0n@YrEUN z@8w0={F1I4(>|kwW_mPKgA2izB==Of9V{Xo|%u6@lk6JlO^TWoi=WM#H5ZV;n z{KPvQc=V@(?$=JqS4R9et`>7;bG0I)=hlI69kTbnIAEr= zfvH}H8C`CxMd^*6KoxvTH!AaU8dU!~9lwHi7(tCe6!uw$>~{g=G>*lp(j16x3(zX5=BTfT@_pfRs} z(jl51gasAtCdd#5NEWXS4-yJ#=_+`oT2Sp$O-uo4i;l*k%H zJ7Q^nhIK<^g@?lYO|atECv0z$Rsw-1rEb!n9f;j$S>Zcd&rXbmAXF8QbxOpAp6Mmw z_=^BTQRSooxau<#ucg@$H=Z+CIA4~Q><;W}&iggj~4&0?d zx+GbSCg#F&+whFniajOkF0u}$afj4FP5Eq6ZN!-{j&5}j4tVuzBj(#JlmlUclyRwl z39Azearv*{<)5Janc0^PqpbTBtMtPmuVO$_Bh=J|%YW2VN+l<$X<~_nf@(}y$HfER zAB&za{RdR4(K{7_8H%}-AI%^wVK!ykd?*X2u{5V|?r5?~&D<>TyQ)Nh>d-XGy8OGz z0(VHzN`XZVeJoJJq`tmlp5jM~D9^B>V&ZWRa#cFh`d7;*anMK^ ze|VH2u1Ru2QAK76l*!rzsrir-&NRGDJbdJH3>IRn{fyfZ7H3jAVO;<=B8P}qyb$+F zOob8BI4~xBW~UO6x=4VFRqe9K(Q>L)wD+VrNQ2ppFZ$_vrG>bC%-4&4!=S&8z$`NiKJ0M__E6)VPYD%{+q z@rFFd=7e=0#O0`wZ2?49S13pqCKh>2=!2)OUf>r=H`vN|wIi_QA9tLFtj*8bHte`< z^DE@EQfZ4Ie=7ZoiUCHAtMV2W=khx$g%{<-S&*Jj%xv(U1Vo1pEi! zbPVzG5HB6Pe2kYLC`+CUF#a#%6dC%v{5OXYG>~yv;)Ri&;5>>r&CKTvT`LseZz}hE zZVEn6a>sIuxmoHzc9=+4hl#$u&tW2QlxQt2&)#O_ zA)>52M3fUph}QCdYzAm+mj4C}G3f@XHcGm*qF#)OszmV_1**|YfR>n25yxo;5{{%Bm3n<^^rVq04+|2F007Fx zs1md#io7`F96z~KK3hJ!By&O)myW$8T}}{t>m4u6jE2ZV3zp2X9 zF+fwq|n zHt3ntZo3Z0A>$p9+jUD6DUK1TYn{dr^l4=m2n{(RaPcN`2-ap`yc?*3%bG&xiSHqK zx4R-qie(c%YO8{%6QuKGw2r2?z5y5p+-!n>gWUsvzX?3x@oJ|j&$%sG=yfci{%?!Q znTec8<_6wgvRDVRkoz7*e!qofR?hOfZg{6FP9i%OE}p;0+)J07ix(@k3(nQ^m9wns zRBIPmt#;+S!!B2@T)KSj{Bppn%LK@ByWxky^43#3=r${UBcOB2=P#aFIsaNgBt<6x zDXYDIMM~<`n%^28A`EM)Y->PunK8jjLK!%FD%E)G?Uki!)h&vT9}$3w~vWXWOv$H*{vQp!hJDI)k!$@o+!oQ1U*hnAxp9^j($S+6SpLInVK@zTS~PbZj^ zXxN_BRRB;gYM9nLYV@pqEcwYNwe(4T$DS;e6>lb?w~~-YR5GG8NkqPf5TJ8^^tmpN zL@A*$mQ}~lQ7q}N>4Q_V-`Ee(p&nz<#=AQwi@)i3C&0O*iFY^P%Tq!wJT-#zcPAzL zV=;=jf8%EXYpBQmNSq%-;+}k|gu#DD!4ze^fZSkJknpWZNjWcw(eUjAgfHy}VWR!m z(P$%iG#Z)WlNd^THv}Qi7=L?z4gLiK+W4r5MfUa713Vd~tG8unM5QG?(#vNf6W#c+ zL%y%CyDiYE{LLH6H#A}F-i7^^Qk5^hD8G(TmPYVqIUWH}_B#TFz)oP~@=KH4aW%l( z3B*}nHQN~0;%b|WJW#F{O#3xqVgl_}V$K)#o0Ax6wNxOVm;Xz={1#q+emnMB|21Cz z4PHLS%kQb-CwiFZydBWx!Cvq%kLLTj$@h=Px;52l8aCIi*3>Q z1w_Tg{q_c<2CIp^Il1qDk|v+uA3J-3F~&`uFNAcI^#~}IdzcZyntpNefQovEO^j8n z;t%n!xCthELu0YeN zZg?%1cLm2qb4Yh;R6K&*Te|N1q2y}@PAn2HcqVipX|(ZwiThv>O;L&bbI_qAw z_tKz<3c7XLLopR$8J}1c;lD!<0eF8axa+QaL439$ngSO~Eo0=x7BIUj$`=!7_~`W% zSkeK%o?2gsa{=gz44*YF_bNkUC1w#r3>6;?_dQ|V0V&~%8u8JoW#k=0B(gZ+-wXcr zv6>xE7L<;Eilb6w4E`gPD2WcNfz|kyK#kB9{14SD3B=0;vJBtG5b`J=p9SL%m4%6_ zRgU>w{(*W!Ta*z9q9~#Wlpdr-sD+AyRguy5+oIk98JYiqjKzvw2Z8vRc##1(+nu&L z>kxztpas(g-#-zhsUCx`O;E^LNg`{yjDq5k+MKR`YYXB96zKwdf)Q)r3n>=he+FNs zl%6xiD=IQZQR9C;Dqph6B=&z5hE1vgG6Q%=567OYQgr~3xy{WQ}rr?%5!u|8d&!Fg(0KMkA@ zp2AOm^&f(-a2OAG&Gk`o>A|1$3VrY->;nl%{x}H^i>O+--5!Hvd=lm72*w8?w zJ&q2*;N-t5l7;`7EL<7qr*6N9AZ9SZ zx4F*$l3>6g#lv5npo0Dr7Std)ElGWs(eOm}jFw4b0$JA!Mo!OYCOkQAz;BUMhG*2X zbV8^(Bd+{Ghl0CAtTu2ICcB9t)3t`P9zGpKap0BZNR~?qg|sa$Vinyit`3NCP!XruRZk@dg{yuXlQNCH?y-d-#7N| zPxjBl(cYk$CPKs_xMg2h%x)O4uPowS))C=yJ)qUl1ogb99*9`Vrrdd$3g`J$R$?G# zvVW3;+8m~=;sb9A6E=YfpNNS(twlT%xBfLNaZh;>LnV3qizGr=(j%QZ+H=yIAyj;Z zJ#)AQRDc;T;V~8zo9~5FjbIDskJyd4<|Wrh<)X$b`5Z22jo((ntR9Iu=pPF%hkk|m zNVeFV6EoJVRE%m$=(22cd5zt*hn)&ac7KDu;~iUHsbP?0N>Oy0q_I+0Vs|vQ5MD|2 zVW(m1XK_JWR*r(=-1=Frhc2omCg>Zt9~6bQ^&$%-Gzq-}^^Nzh{ynemx4pi{LCay_4}_hWcq5>)v^uUznaQ7Jf8N z6vhwq^aC~&C715mPZZ%*PR`~`rLCOZSc>_FX3dyf_)IAsS?(U^|7^G%@_kXTV zUB5sg{gR+X;1SRT!lU?baCq{z+kdrdPkTU zd;UY&@|VW%EPmc?T~UORSA;6Gin^-hHB}LMUKd8*Kv}Ai%BMIt^Csu%e42BsU7pEj zIJfgQ=Y9D;&a?R}=l%J9&VO_H9Onc10nP{WgPafLhlH6QcC*XdggT*!^ol0`0yS1; zWOaLfyGop8@I0Cy#j`E?ZY%k*>Nr!3_fU+tDY9-~YhpuLG376~{~h@q?oKx=`bBPC zzoSaqO)c+g?dEikJBD%huB#jP&pXvU?mkc)+(NN0sdpVQFs9`9i+_)aAu)Vg%|9Tv zi4pMgpx7=(kv}BH#5nQ;VnXad{;=37b|F6~c8fj8C&gajAU`DbiT%hQ5f6w5kslTh zi37-|#KYns@@X+C4k16{9u<$QXm@n^>+aCzQ-y`|=lyT_Lw71QE~I4W}Dm^l7c zN>#Y*QSlg;o#-h$DSsa4vQs@}Pl(f8_GC}l8SxP+!#Iy6rL7YiO8%sKa{2N6<48~C zPa%CG{{+(0`O`?B%%AC5TTT9&n`(Wey?R(zS~XRv?&v9{^eK1Wh8owoXVB`q?x{PP z_Z9aEPET{m)8eUhm3cUeo}OXaZ0lL^bf?viKy#L9sKw93Gk^J0_&wnsSy%GsQ1@)> zynAj#Wr}I++_^EuJ-4pqXWR$f{apIAIM4aadF3@fe*wMf(n0AAT3!$rCX~2!bbb$i08klb5EcX&vfW|DK54tI&-+AUnh!>QmIH?RVFV5 ze}AMd1{y!g1GpSu9a`t>W4C+)~+dyqNT6xl*}5v2?FD%F-2a zE2msVul|zjlp0dHRo@Y)EcrEgYucV;ib~n@9rRqA_lxB!8ZOA%s#7nPR*H-6k#=5i zz51ia3+1YC*QR}UwO%Ru?)0)(t2ztiiaTxJCF3%wMt`}w#E^xBMz!RZYt>-j;*Da} zc}~_=mTLY=?M7rAKYHxM?A`b9cUOV?2OBCrxi?$TH#t!HQhzYKoFt@lwLx}|O?P0iOrn4op-?L%Ksef{&w z=hX#GXhOej31eM@aOIkMsI`nxr;WdU@S1W$`M7dLd09beYC{3@so6-A^QEm;nugj& z!_i#cR9niMkjZ4OhIEU9XZfxcW#%ij(u!9O+x^dkv&dP~LQCr)~e z)#)>!FIK##rjvzXib*p{FBQF|N_jpqW8%o5O^A%L@5;z*)CG1t$}G8SqP*yO{-hCE zwDr~Esw+omNe${CN-;w*C)*NsqD+T@6Unp`)l#$SxH_uJy?EQS+qC?4vfGzw202>v zP=BF?yrxvo7>cj0*z%*Q(nLwHCsdbpUtcy>bnld}ET>u~(R!ypqtK!YP`#nPth}OB zwU_Z0uVgyXYF=cm7FS#-g%_n?ygDOgO-3nK%4#h#XJ%f$cy%r^>O~*(Dtn-s)Z{}n zAKhIm#dGW|d6ZsV0Y#zyk?ssNHKz_@j(_st{bpz+Gu+dbXA-7YwWiusgw|3aUa&)$ zhX#K2*}G?W9X@sX=<()hq$j42FEl6h$Q0!pt2F^ZuF2J+AL-D)Ni9lyZmCuknAU2! z+VEX(E4zI$eZeoUx--Ou!7S%gd4!lXdYC1B>r0sZCnTW~sv}C%z@{i0N~n)3&3{yA zgsGiM)AZG4t)*`$@+YAt)D=U1#y3!>?Zl);@LSiKX{JdDJxmMZ8-_qzVWOUX^q%(3 zFtx72d|IKosV4Ky47-+7ogO}X%QUs*cIgf1IE#TjD`{8m3R>I2{_|~%TCOfmPft66 zjx`R9hny*=OuH5AbzXS3V|HOGr+=K8O0n+YX%4G++6inFU9G#Wz;g=3N4!ZZGH8im zqHe+3c)qAL{KzbOMc=;_>DZhobyJd((XvOWg-XL)LZd#`qe7|HsQQr|zp$Fye$6jd z+RvU}l<^iu16{u2$}ANZ+?c_rzwH1D9Q8TR*Ds%dC-s5bRjEt*CM zn&_Ua}iHxa#Bb?O`8r?EQ$j_&&Jk4{aENT&QDwgU0`0&d93}Z~ka# zg_+P;*MZd3>vNdrDSym!471dv1#gpuw;4x217S94dkypYwn44oXR>c(6F&n!GBXS^ zy2h_a$6u;?je0$%FUrzV`G)KGx1j1|=(+O2Y(yq1UUyI5h9==VY4io zT_Bzwus3m2FM1wvlb8$UXKr$wl`XPdc$%AKxXCo;Ldq7U^X2*ldawu~5Xg+|XNw{! zO+(%0Yn~gWSo>n*m&RNly05UF;bJ@J+eO z6OS^IAx^=sMZ;~34Fk)L9K0|yw%ROUt>S)d@WHS=u zZX)%4_BYG+=vHjG=E=Ie%(%gT*|h;IviKiV4Rr_Jwtv27+wWwa@vd2#hG#O@ZKs5N6H6X~ne*Bz8taS5BC zG|b!2pnsT9&R`en{~Glf8cW!rl_-821X^!c9T3_1hR(GQPS_7GR+8bFwYp1U&{KBe5+u&+P&vg4q4ZnO61eCJ6nWaYx`NFot!s-B z$mW8PS@&kAk$_@RzrpScto(E$jK!cs0?_6J+J9;1!lcDo(iL*~3MIpo5Mq`er-c01 zWJbQmQVLmQwEj8+jS>r?l}tMtNB}~6sA$k_Pctcz+o?;pBd1+q9V&Z;3NJuH`!y1q zgX}mB)qwmNkiB6@Z;t-8tV(ih;ytU8)E>~}>Q>Zgx1}&X@=>@-Z5k|vTGI?QZ;!7C z0DlMp{P-5kb?|TOwoJIhh1l8R>1ChJUyz-)^8(Ni7TgVF1nve;P2>9ipdXtJGUU4Y z748MDM1H5!%kQ^)$$scwE^#mYX!~D&x@B=M|Bj~&J#ioQuk6F}`$UeMBqaR+Bt3Su zPTSQgVt^@WJwP2xbx5vn4xA2-kt6MI<$s``m^@!*%4^wwE@4%K_-W|pPsC=@QpnR1nFK^k&gz{*zU!c6rlxv%IE1~P`39k=@ zzP<;ZcY`E!%7Y|GhwE+H;xMQ*vantX_6#iPtW@8P4p8GXM_E7%s>Qq^jinYCb ztp)NqKHS1f$>)h~_hvc=#;06OAi%!Bp6*lyd#;e5B=goK??8|mjOObHKUtg#Ui;+h zuTH&o=+&u1laJg}r-E%9SehzI(I{7IQMt)=YZ50X!WLdI)|nWQU@D(F z#*}iA)=ItE;jDuW9IsI-;qb7~s8nuE2NO=$nkP{@_UhArbou%X@hJQ;lFJ53c#4aH+W8A{NAkrj&77qKRr6{#1YmGV}lP`ff z;{zl^H#WeG17de_pyN{>;r_g(hF`9r-&J3_Krij7z_~>R7SrVe*rd%6Dt0*ia8@O( zV@xQQsbYzeGW!h1N|;YaUZUa7W1$mTB4-slo-IDdY*fj0|2cVw-+xRT4gcrhZfu4@ z;~JdI`=0IiStGz?f!+oLqBE@t*JS7vkup$1;3%%Ov~dPXM3LqHZjPQcItvdXA6G{- zZiC+C?X4%pY%ietPXbh`P%27O=Nzsr)ahhQ?k!9e^iW?0NGhaYeoa3O(~uJSTQHMv z{}I5K6`HLKKoq4ZI)C?(>1n3nAT5!Gc`_?Qu8&dpqzE6lz)I}`P_ z!S`xS;HXln)abM%>F!J(<}(A1CQHC~7?T0lcqagHwu8E|kxp@KR);4k`3*|G#0IwH zuSMEIU7n^Q4u8`=LCGH0<66UK@qb^OA_?$tZGm*Q6Q{^wfxW}+=#0gZP5^(L^})t3 zt5Uosr_r;<&$~4FJ0zpp2Z8=pS4OqAj8Zt8WYmC+8jw*9GHO6Z^|p)}Z5e$%1|@Ku zkW@$$js^0Ieg<-wf*c+ucmX-%fLt$)C$GQJt+_tGNq@Hb=pgVu*-E!%OMaHt=}k($ zK*<+*3%YAA-=c)5m( zL$p86`}U`^H|>2H*W}l?+KpWM)|U6=_tehy14Wb6363%eZGxb%@>%4~l#jgu{4-H* za6Cn)aDOZ`7eJW-N^03`rD@IOm5^ZFoNviGYE5b<(qpg!$gMGjLEB)bCKH$VnPr=z zKy)h`>MN%FvFL+zWEs}<7=o{toJO9U!ZEHt38& zaT~zp@is`_Nu>m-)FdWDypM{ZjZO2Yj$@9)tzCe@>gE~xyD1hGrd9~lehF0Dx>Oi}w#+h?PJHufM)FiQ@M+}>S^pvU4=C0x}TXm%bB%!dgZJbX`mI7mHA z*na}H=#}TLU7Rh<&h?6SE)nl&@VSd~&%g9+;o6H=K6dr;Gv{Uk%b9Y{*Q%}^?4*+` zgO%hE+Kmhc6X)9JJ!iG-F(Tk2C8#5HdU9`M(aj#+48Y;v@_ctSvglfj;~2*}$I5PG z#VmVltN6&-jmSRUQJVYdotaq5$fD~?9Df_VNQX)7YGB(@RDGOND-X06^Fpoqv%H zP5$Xt^K7<%d=vT0_Dv++Lehr{{1F8k0w}$f-nB)9ZEJd3n`6*HXdt7l;XSYd%3k! zCkrPZnq?vgMPfP9|^ny?rBe?a}4sA`X?WWt%EIlro`wS-Vc!tVRZbgXF4J zn?4$;^{p~spP_Icor#`msO?)c69WVfu<>WkI3n14^P04X(y@|x!PD*gXn$wz{3WM%7JSved7AM>|9z*&SIE1P>5U}QdsD&c8=;y^Q+}^AB|_8hs`6W#<|x09 zWKC_~gwW)&%Dv&DTm=)wI?jSqq9|{cs~^0?@8?0Nn|RQehkM)FQ|s-u%h;BsXSTx4 zZ2iAkkbkymE$%nur?;#`ihu2GWRO7#_R^;m)tc`VZ{W~ZoCi!L`UeOy%lAEgFiS{aVM+MXDe5Q)wX?Eav+M-7CE< z5?QB-9Ac}rgX3`)jy{$)N=F*DMn)&6=p9)p`4h59%9gJqI`HIQVt>e}3H=?4))<_V z)uB8sEY35qGL-kdlWM|=HdVUp6a6cOJS%c|=0)3wAX=*F1tJ7OGTq{IZAw;JjT`Y3}Nif2ziswN0r z?wAdR%8x?(Hp$};$$#5ucgY9dWw`&B#Ms~;kW}=}&d8rq;Xm?` z1H-nBB`dC^Ykc|7@$E%CxTM{a?<7DY*mIR_(`n}+@38Z1*?;%&Bn~?lA%0W_(L5f1 z_E21-`{vkawD`JZ0mh8wc+!YQ+hLrJSQg?-9b+C{%0J<|4)V^MrM5S=EPw;(G?q|& ziRAVGYk1;kt^YOCF_@;e2a!L>&j#dI{ww?HLSeO7t`-Wxj`JV*krjQ6B;5ELD~c0o zQ#XRl)Kqd;Wq*4<1%`ataD$P{bZ_Ofs~jBK>J6Vh$B08rF|wf#vEW49N*!H^U~p<` zGdKyxC^+SIzvQYd#EgL44F(eOHjlwXOx+D+_0lf{eF=TBQV9-h>A7dFTN?U-IWNfy9+{eKw;eUkAluOCNBp=g*%pA3mjq1L+ zp#O4v!%h>v45p4uPapZv-<1Uq+PxsTmwmi4?-bq}zE*2gL~_l-1Igbd+4(EtX1{Z@ z=yd~<)6NxW@uqJ)?BLjDn#0a~gTA8crE^4Cuu-R-+-C<9b}}<3{)X;ia?1l}I!I#w zT$CT3k|;kxhY7E&3K_uZ1_txiORl0a$$m6M%7J99$>|)dDDEyI7&r- zlemExWnW1`f^seSb{M&atW?VL(`~>VWAHSO)2Nn96zDKx z64qh)2V4b!Tl9SyM+BGJh`m_hJ4-v31oClFUw?9WgmVI^8b>G!a-##$4|cxJV3T>i z6Kh;e0DKJU8Qv4{Wlz&lUA}@XM7d|=VuNmeFY`1bGoCI$y%2?ByDqY>zI6HWm6@wo zBb)1~2KI*1*u%a{37-ox9fiT^0m~AlDF90ksnQb7C0(5NcoWzw+wrF&BnJE`k1J(l zxPNP9Kibx|Qe{_kEg7Fs{*IDA-i#%Bju2;7YobwcpJGf;zS=Oen!&F31O9ab2Lw7Q z*gBB%MO2?r&bP6bC5E6nSB_VU&zhMvYtNopzgcVVjh1;b z1P*~fu)y@~8w7F(vP<%izo!l`kucvQfmGx7u-t)a_OKYbpnQK3-e@mpw5AhnIt+05LHE`<@IA_QQ{CRRYuY6M5Uobeo;uz`bAJbo-s( z__W=;{|;XtW$%Kizpsm~3IyU13x{xtS$OU9Rw1kiLKq3>P6jxjIN8oI61sm5CIZNh z^nCz8{%v0M7?0_)uuK>MQYA$!*V?8!p>RUYII{h>efhyKtX`a^%{ z5B;G(^oRb?|9aZ@nPFg(22(ZVZaP>-45o7!Kag@a9V~ytxP%ygK8$KN9W0~Ti!J0) z?WTie?Boy##s??aOPQdcCt$(@`G#N$1XDJc9%1THKp;|JvIEl@Fx7$S1(*myT_nL| z4W`pzQUmL{g6TY%s=+i3CT_5v5txF&R0O60Fnt2k5wN}uudpf!c3km$hRde*)J5|#CQROG@kBpX=gX8Zi?eKqOb^QIj{r!F~?|T`@()RbT zb42Sn?Gej-GzLKehZXs_8m9x*cRI{Ahpp*CKsKTZcW)fqFl24`hCo_t&Cd zIVS(QvdO{9zprNkG59g)erR`fTTcgfNA!=nzb`iU7dPh@z6l!T=lIu)|CxO-XY%_> zCJ+cMW=%%IB7a@4`Uc7d7cI7)^zr4{p`Va`8zQeD!>psfnWx?kcHsI@GSu9UIqk=a z_G5om0*<@+Y|7ofcgxuWyxjdf9QN$O>JNTMNQi@-^IrT2qojbHukU`0%VwvZFWR0R zKw?-nATJsIohP&(cKY=?ER0q~`PvmEcv>Q*Fm?j^$2|X`KlF$G&>#9kf9MbWp+EF* zBIu4UPrLV6_#hv;yRH8VA0Kq?)%W)I=iq;Tl^6yW0guKI1Bf+vRDtM&XBrS4h&Gtl z0FSERIffdsR=(~=0|>z5N5}nNxji{p;2-Q4*%L5K3j>HB1Pwt!JR#1YG!(=g;s{Fi zgg8MkL5A9$IsiljOp-gliaU?7H6e#Uz7kl+1N4P#!TQ0VHnw2SaYwcmD9Ij_>ji)D z1(Orl2V$o-8mx^u+JYPuc;*SgTt68oYrk)0F!}DZMS*pH)Pg`1z&r}n*KtQ0MsI(J z9eAb;YNH93yFl0v$T0>J8kF>-JrdMhU?&Md#CCF+b0jE%8)C9E0*atSOlyZ7z8F}J z+)0>L5+Wdg0CMfYvj6&?-vl+;9a#sE6A1D#934=;p%sYR~-3;F8 z%Mp|Y+0m8wFMa)bNB`CR#E|mN>M{oVK>ub|W8!U?sG8x97M`F?_n&4Y1YDODSbyx< zANoUo=nws&KlF$G&>#9kf9N3Xyo(NlL4auOI2`;VvFfqw#86yVUbJ=)$nt|hp-5tY z5C`8TRvqdH$AUotOB@1T94LPlG+G=6#mdtLGy$3e98v%u4u#}l6~H1P01_ZR&=MPh zh2Szu3GY>LIS9Tm5JjaxmnGx?Ns0p)(MTwE{%LNAut?C=5m^ z41r*q^d&!g)PFx7^9BN#!-(Be6-tN=0V0ru06q@f2n&Z2W@Lb*1jv6e89Yh?6I)*w zl&7bpnF_|ZYEEE6o75)K7@xaco_X|LyIMn#V(L%Lw&~G2|Sb2z|wId6?JyJn>uFrHC+1kpX|#!NUG)#54BW?YL3} zm$yaUjRQAUWY#+6dc7xti**{{DS5*Jr;wQ%=dWzvwi~9aKk{ztXqTbRvt)~jBTLBA zcu56)t?OT0A62^Gaf_CvUx6P9!d0#w$~K_dyu3~vHfvwb%FmcupD=%kM8`3);=(8F zR}) z6d7xw0!UFw@m)38Flv89Qq6v`4y|W}n9iWJYd*60 zu?fwtlmo_?3d~qKfEI8(Pa{t)R>j57&s$1R&>rnB;IZGAfW4Q8ptlq z`}qojs(=$1oW9`9wZ_a`en6Zb5EB3^0p|Oc3WZ`}7WJ|HJOGQ8-RmMSFz|O>IHLbc z*?s^KMrVIYDD)c^41oNyc;T3-*eUQpaaNbbS+Q$k?d5F7OB-R)*nY%|IlFJU%p_X| zK62Lt37Uc_-?Eydx!l+a&S&cMPJq|k^1IM@NO~Mg0Ne9ezQEg}W7i$^)Drp*Z%!V| zj#!8&rlGnmLQ9I^i;J7~Kl-?i@#^9E1aFz}7p#BWY!W>;%}faT(~;bZUHn%Qw0V4` z{7vUa%2~Hh${cQF79Eb2&tXVfl&&%9w6ZIST)f3{WZl|X6t$=j=5(y&?t@Y{qcaIm zT1tGJ*$>HqbR_NR*`HfO(9Xn>r1cu_Exc4lH|Yu3gzB}L+dlOZ()3BLg!0=@3EUy@ za;Sgcqi?!o@OkCBWm&Mw#hISB77qD9G>$iD_Dpw89)T^9zUGc~hW~2mqT>H8rbGw; zc1;P-k8*u4FR&7LZ&6Mtds{z8go3}Hix(Q@7yRAmfk$ybOb8GGkm4AlC%T&z#bp1- zjq=}_zXcKp-C*aMw&`trh-OY&`MR;o8|8nozIIcc(xQMc50!g^k{7BAnKm{Yqi1La zlD3tz@#Y;RWhY-SH!C zG-*<)y_|AOvtLCrO@$2&;O|*IYAAmeI13>M?A>qe(Bbb5s9;z`Oau^voj9u!L;>6` zfGtU}Fk)f>((h{@8-Rm9KUuipHRGOSEnOw-yeZx8SS=C+nUS z65|&V{_nDI|3bDO5OoEkGy*Fs9f-OBL?wM69052G6$QxbcLjqULjKFHbdP^)2s(J# z`wA-Q8VEW#I@$WW`w6)Cc>wa?o5KJRCLsjlfgrp!L>J-({$fJc!C(&aSiyEL5bd}V z;ukA2kH<-?E#YBfEwCzw#&>h`D)-U*1%A+rS7WsCB?_xT|>zU@h=G2a9k z@hHh{7M|Bd`KWWOsoj2=bNOmY?+wcDlLDxdUk5l49$vPCFK~y)(GWgVY=Dg3WU-|B zV{uy#+-C-dyGllETbo~oDeISv1BFp)N(77$~nEt2! zG1+ks%}rujo1YOUox6X`zgYdYk87~z1ZuPJ5EitA-PyNKOQ-fZw(-S~^#y&ckAc`a zF%QQG-z6?9;`b8=OtTpWv2uzvbylA9yv{fiGodDImsI#TMcCShN&Z%*<73u&MHY@T z4E#3Z;t2`~M-GvW+8#}FvC&@{QOnAUlz&Sd6)2lMWk5@(%P4=5ewoQhn37A9CMZs< zSNnl=)h8J>gW9RrlZ3W1M@BF3^@^Lz$}1uZnaS{4jkBBCt@L15T!RN_1}9q55^+O0 ze3Z*@TxW+KzF@nQ;opvoR!j$?6;r@1J^)VJ|6z0eFZcNe+=slVhZwW7H<9t-NTP$T z2&l=A93hefI9Pv54G8{dh=pXuLQu@>EQ{wAQN6}_AbR>#&L}af6{+dqR_FjVzi#xR z-CNLH{Af;u1kFVrdnD^`pKbm0geadi67errcp%Et!7I@B7hJ-MhC=i&E5D6w0C&oQ zg*sfFE2Z9W=PedNOMztL{@Z4f{p0QDyE25%Jf+K4B3yqkHL|q1|ugS0{zUv z49f#7Tl`zBqX9TFq%KV|$+!;Pqc(M;c1ve(L_U7;;>p%X=9v%tzR0ALNwgK(7Xq^d z`l*P%T`hki5LdV?lo%B0GIqEE|MEz8qk{jZ^ZbTiZYD0YF*s_QFBTEcTFNW0k3HNv zRzPC35m`N}x2bWCn3t;iBSiw`(d?$7bN#*odidVAlEcY}qEIbo+}KzX@}uQ(foPi4 z?}HA9Ly^%mr$FAxpZro9aHB-y4uisxq`yoL5XXP?aR~QsG8yQcMne_Av6TS}B*9s} zC;GG*0UY`p*R-AW^QpIkQdN}Es$7%wm3@pvVKcs^i@A4$8lMNxKRgA)ar|PJfI3A> zDFg_KVD>x!0EmeQ3kU(=ZU-w82K|^9)n6FZ3q*DOThz_#mBF#IT2@Nh(fyEBB2 zx8r|qEng%Tz_DA6$>B!Ff=egs2FHVDS!&|1EMMbzp|u=_`W>&L3xHK4@Z6j zKU)uPgn=VE0A=r(7frqlMB^fWXl%S69yxSziq^fRc12Y{>~2kk0nxqe|66}I2#ALLb)yTzY;l=4aMUuLUB{5@>r1p0Y9g8rZX(J@>Ix^wQ;o$?ALU@{eA{sU$@BBe;JE zF6QIB>^>HC|Nfbve4TE$y!3Ra&{oOA$%rsMUvs;dtn7xfnREf4w30k>E-J>jZj)ho z5}Y4QAipYXx9}=6bwYO|HZagAKQ$!P^>HarGE4g49Kkz_W+uhM0biQ>QV5^N5BlkM z&Atyu5FpI9M`6p)mXD~Qt}~rwWEy|D84QsNa)$J6^1b0NamQv{?v<)l*=!YQPQ4^J z?P}<8^?isZ6SFLNo3?lBO53N$pN16rZ)E1atxmcxPFv4tjevZ46*x3@?!ly8enVHb z?qhTW#$I@dmIkWTX>J&(i9*z@w%otgFb%*S8s!6 z9;4(6J{^8hi1UN1>cT|NX%6g5mADc_4`YUolMV4r5$KMwMBTfg?&<$tI<QOc7%e1u-K+8 z-{QjSPXe)=Pd9sqE?%1U%j|#E4b+j7klISuIMIXVGOC^^aD1InWctGOV+5z%W6AxE zz6NLqRSsCB))W_EYjwSR4qK6mI zfc5U~+!Qbd4Ddy6@ICf}w_^zyNilrTslko>-FEtv-wVOK z^)SNM#tz$GEqb4B<2>`QtFBlKcTT{PL`^M~=5N@n3HUzNybw=b?i@eIzYa%mbtiXW zg_#DyrPfwUC(8L%&rN?#Jij?0MU~_hD{;c5TuaQ`tUKU1DZYc?WGk6?qe>6sVGgSq zT5)_7mr3X?qq3T*6T#%{BM3@!1wqB)^NA%gPgNnbMr&uOobH#8k~ebP(olWQW(O~2 zP@E>SP-WBIGLN$al5*8mD+9Z>cpf+f!XmnRZkis}@uZ2SAMAfQh3gY^jo+C2o9#^J zIVr!yx4KmpycDA!pf9WVcoWcYf}k$rmTJn3{tpfa^rO>phla+V=@|x+)v91Ed-=9s z%3A!~mvx=Z3Hyn3_-GPkoNbKx7wV_1iw)}CeTe|XbADB;oX1V5rTIlDKbfDyY!6z| z^f49>xkzr>v(10=UbmN-=jd5oRjxd$x#DQ$VZDfiL8rfddU`L%8Fs^jq_i5>y4LNT z{nKdj#}LTt%PB}%CZDqwTBRbVmY2CoK*&#h+<53Ij+9At51A5HN*--K;Ps`#%ile+O_g zFN-zjs?mQeguw+}qwK+rB*W2z+i$aRaR*A>wf#FfMNQVAC*6-ty=uHGOJgJa%~I!) z(|WprkNK;JW9DD)h&jiovJussr|b(9x=%(sZximSe@eNoI8oINm+C`%z^7QK``^_aLVJmmsWIs_Vba>G@?BjU05!E>c2}TV ztVnw!z>z@-bXVCd4usFykb{D|2`JyS2)1dN1uC%>kq=J^zNkZ9-ayy@SfA8RWCGGY zpt(Wf4b)Ok8a$U=bf9)nV1oT#P--*TXo=nV%}LDT(-4Fm=zGN*e!n+tx1XUkgpoBr z&<>60fnL1!`^30)>`2pAfJa6U|4;GKWemAmbyZ8Ih$6ZCg&1~`L(Gw7WnB7JaFF*J zDnKgEOZiCFdLh*t;D8kl5DUrqu~v;@O^qvyNbZ zDmE&T=e+%PtvP|_&;v0_TpQw>j+xwr!Vu+ejN*QjN8ZigOJjdXe4eIBD}a;OsLIU^ z`Oofu$>4y2FEfbfSA8c!UuG*t9}>}^#Cg#KQYeH17^ zern{S;M7y8)W2+OApF-T>&G)-ppF=JxrhTuU3($hKcbEag_?p6foS>_i=>Yq6bj7L zPt>9=Pg2Ms59$TXFh>l@9}+8?i2!2b&sMhcMAkM8fW74_9mW_kbC5}C^mblAwhb~> z0%*@Dv)}O%`Tg^BZmnyVFUn@iL0B$seK#5kYyUyHN0yPck&5XxTH(K=t_NoVm%2(& zM;;;=ML=_iekP(xOcqX?o7zCAbk?ItE>@up#3N5b&1G}>Z0DOqlXznY6y71r0eP(c zOq>Yoe@4w7Sij|~J!8PV=QQ|;`0WV?ia2pn*bvzJAA|pJd9Zdya_K_5t!n@kQXJ}t zPl6uFc3#=c32F6!ZXp(pb%lUtbb<^sE|hpm|e z{YwmnFbMp+uq$2hm8Kgh=IwO|rV#tVrLhesfbbrTQb9RIc~>FfM#x;lY6ugBU!Hzz z4i2g|LDbpAz&FLER=ATOx4KdZ6gx%?PSj-owyJ#Tcb)o~(L@fiaA1DU1Zcazj_F=O zsjpYmZ_qQ)GI~q5(wS}X5W!XXxa-_wqV{pI*p|rZ(H|(Ch~)wvi5*fD zFb$*>qZz)#-AZAN_H{hoLS_6nj5(ocY|X+#EbSxnA&g<;;ocXbfaMpnYIqkB&*Ppq zF+PjI$lbk+gwgu`>4Brg2A+8YQ=Pe}an_5U(tzuJGO{l+RES04;|Vo5QMcVd-XjIU z33%pDcl$V@Cj$B0bBW}e)WPL``j==TfJX&0gs>P8P9^VeC0Ax$#)~BEb47U0DRb+! z_+br&2y3fPg{o|?#Z5{^rqu&e+NFQA(r0GpmgY|XOpi=Vg5ML3q%uskIWz{-nHju3 zd5@u=SY01P03E9*q-3v%mu;k7Wq*<>x<;T;Euy$S}9%P7uy(`@-1wmoqMP@QqQv!Ir>}G^xBj?E4DyT+Sk%zcORD#3tUk zuaJOGs^9|ijDQxU=g7+7qJ)MsKv(;vMa5YA;V8)YR$NU@zS(!_7|-K|rQOuT$>XJM zm`?W_#=3n{WjQUEZPs-!9Wph!%Ol0{>(5LJ_NOhpopg+g2>HLX0KOOGSBEgCjM*^e zxvJ^S^i1FNvA^8SLVlM&&}nY)i&V}1w82H<>RdMJxy7cub?gy02@QzU05$&1ewGqN z4A~^#NpxDbA!Wj_R)1r~{O@hWLDxeO>equES(O((0yc&+RjAkB53feO$;?~w8VPC7 zi*Z#pm8U6*AL9b+wiFKRhGDc=jj)g8&BNUm>D)J@tK!TYl5fwPN(ZiAF;=AM>z_j{ zD9h}^c6y6cdl?lpFdu zLfuV`(8n!3nvd`Id@KSK{4t+_j?ri-1_+rO0jhuSeR+c9+&Bgb03!u0g$?rR$9~yx zef=cJYR=EzDE#I18FYDVUP$i9p6~Qz-P9oM^qEzCG!~=^NZO;kIap+mIcn;Y)x^A- z(No$~b`pf)c?+&sKyC|y36RH_%-Ll5byomsqNR5CDgO|FeTjTk_)+vRh3H%sMUv?x zBZrWIop0Y>&E^&|Oc4c{My689$f*(pZd zz%S3$vSEy(GZx^jHx*i~duyvL)fL_8U>Q2MH4OV;r$kNC64x zXDBrV&Yh8^-XhPUSz<+%@ue-@jmv))Q^-!<{20u4q+Mj9p$R^bqo&PL~=wcQ53q zb7eF1F&NV~7+de;YqkjhznYnBS1A);XCDZj$tobIy+ybWwbji`)gqzTo%d zx#iz}%0gyfz!oc|*vW_2wo0x*N&K=`{E~T;hN5{(yfk?Sby(L+(KculKk^#T0Kp zA_(mQ);>!;5vcI*h=*UdRX6bg_ob16pOc36%vMw;sR4-tv5#d9mv<8&62RrW5xn)9 z34{o>cLL~#Jwf}?P;?Hk(0hA^0j2Q{|WoWmmCMFi3gqv0`2}cc-1J4XZ{X zqx%8xghH9iI|;{C2)1LysEUpPINF;dTuKIXgvlul{%v!tPb^EjzaBHz8L1&pC0q!sE?6ZcyG#iZ``w)J4P~>J@v-W-$|=6Q)u@g@QtS?_+h>cPhuj6Sn#WW)v!mEgR(|!s7%DzpK1YA!Q@CF)!QbbT6l-)}g>? z^q~iTjD>>_^s_N9mpnQOcX?I(9oy70nW-8t=W0cl^-q&X^Uo(xv+JfxSgw`^E=oh2 zM`YvDWSWi!p8&?rr&QvAXGjrXY{$2xExTSKdd&N*~SBc-lmRS!#x|=cfn6*u+ z>Cxw`D`&s*EK#S@>oam`+2~F6(W-x5ez>&hg0fun1A=W*ong|4y#3I@bTRjzo{?5P zHqWM%h{0>&4kR;tbz?X%KkB^Ujy0jG4bIxkzZ!vN-<%J%haYit#Uiebc+V+SHzb1J zXSapDh(lmBukyHAWGNj$mQnZ0Kt!vMm^d(Et9hk+dP^>iA9d%-g$DU(FkzjldGW>X z#7PA;e=@GH)5e|cZJ^pHw10sTd#O3o-VIQM4#vE{gR8=E4_6DwbUn7<{Wf0E2*lU> zdvTX{*a%;fF_^C>2m|y-uCo}~v5UvIX#&8y0nj|w3(o^Vz_bXk1G*s0{2KyluKkpo ze%|dGq?K<)!XvKzcU3Zo0tZOWB}cMqZWrg=Afyd6Tn`mK6BY;&a+E6)DiVD2H;~wE z6Cd-VQ_#3g>)?AyyLL+1Ox-egaSSW!U=l_fn1z0Vzb~&f!|gJmX1Vf^S7*l}y!J7# zCr|qW%MsJmmU{#MWuT)S?KNbZBkmARlJebDnTJrV$(hdPR!}$suqcM=IvYnmqJEG5RNW#$PhZ1-h)7L(ziH*{eQ>aL=~`p81@9v588)NO ziLl6s94E<6m1aJ)NF;Ze0O$De=weFq60wFbh zwBaE$y_CQH%BE$Wy;FHGoe_^2F2b#=^JgaPA^V1p zwS#dORVN{1v@@$lk&<0DJEE#(kdoXo8mIJYLw61E+i%(hY|Z-7J_lPBtR@+!b~%FD zl7uvn0fcq>R$=0A%&dUdgL8W&)iHpzz?gw;Egsr6mGJL%H|eg2V4VhCwS@nVgwy~h zHG@#vY-bBE$_uz?6%0~6%PSJ>ZKzMmv|x+*O+?PZ$kM;V-VUT+>LFne65&JvBpJ9V z=_^tI#swh>#>xJWyar0INL8->2oI3K0162du^<%m0LFv8qjj6M;yv_hOdfZokreC4 zgvYSLz$u1V0fSfTYU{8ANP9>GgGp*GhS-{;0l_LZobrbx>jYapGt-r9X{|`2{R26F zC3!Iq3`6Dd^o_&k7j2hAg2S{VDhx-ljMgn+vp8e7)}=f{1;ctLl!TK%9zLgfV?c+G z)fN1=$7I~xyeQN%D|%=D-87X5J>W~XC#|X4W&7G*g}nnk;~>i1W%KWVM;SpYAhr5oM_K_LdalT1|I_Ib zJxdmXkmY?h#2Fw=CvfRS83iuSd_vTwDT<(vg4pqiN-crdh36Pz6BFh}u0un>+QPIj z2cskBR75_dq%io{!n=8Gp%x$;YgUkWN>%*&#r%4Ki`YlA^;3z&Q6GY{Oxb3F z<@6q8hk{+w3?4_J|16TfGRggRP5o+0BZ(e&O%##Zm#4Fll3%&m9~8U^zgXrAZ`5Swr(lH;f7Ru`X`d>Be5j`;C7*dhg3p z*f0G}6eg1kT7uJYTc@DKdx+Z$=~W@1 zIH6~kbFF1I>2|A)2>HeinPcWwvQA|H<0alYy_q)wP#OHz6FpSF{5#jyz##WgAR~*m z%`(JA@aRgg9)6i?dD^EA<*;FW_hg*KSYzdHebkhgW^m0KBgP-fiO5PG*7+;8?ar=< zAgyQQ88nC-9~86NZ_OT$yduL}=c6I4@BcM&D9=C`Mb`4^a-RjB6)@|ybe0RBmTV=P ztEk=%Fu1joELzyp-eF)I@w67zv5}VzulTIuj4C?_ykQ;-93FBigeGvFrvDfxb+aEx z>S%3`-f0Wc8GfpXPRbhXL^R_&pP(R&kro7W7od4(em;-z<79)+Q{6Du-h4M={`~Aj za6)PIJ`W>w$r}$qB9iTw$h*-r2;8fmf;bBTa=;CHqOc+S3G$LkQ`~vg4|9z}GskvF zw)BD^)Asa}X=vVoP;Pi}f5J2^y?|iZe+3NpcgvqP(>P4+n3y3=wPaca%7!|9ElWpDs zjGIUq=hb|Nzn1)`B+v~q-=db&D7?q#p8J2%oa*5EaQGR~}lZHCKjhv1wFFbYi zJb~Ac&0BTnGi%zrUKoduHDg&sM+pBgalcYj8MC-J z0Mpiz3zx#FZOdoz*Vd}PM`0!l4k(a%ih{w%? zG_4!a3{`6GHSEC9+Rr!BPMk;C)P^`t-dLRZI5w8O@+a|+rF>fbiLw%>6$K{-+`f(g zy1uAjbLf34r?=r~cP-^e$nk&s(~oi*&yBawe7^M+LIsyS zxmi|QaV6I14wg(!CZ7JL4lAQskmSTuy5%y6rY$b*UNbb6b&B3`R~*b)glbSPbtu@I zvb3O$7uW`Jyhmn;NZ0PYmWZ!coXUlXa5#X%NBHZ*3^<$D zjP7%bG34#Lm=-Z9GJeo|e}aBy7$PHJp?xKor%J1Z$9&Ov-m1|w0k_lu1_JV$*wS2j zoa5$4IGfXUhS=ELT-&_spGg9+WH_3a8!CGP31G%1R^jEz-9@9*_M4m=fgR}g+KO*_ z5cRPdK0@t+@#WGSa}E}2xnvsZZGNZC!Ko}bb;a8p9$U*<-RxkG1Cv)?A0m;`ff}NP z!w{ow6T-AR_9)HC8%QL8MtTyDO(pBcKf@Hv<#mN8uiO#NS_xw7ociWE1<@%vh8-mO zm+~$XqT2@IDd+S^51`#3;^C-&CKci)yc;J4$cuj>R5>c;)BswTrzwckY!c-`oG=s6 zXVnZYuaQ;l7>$Aj4cX#20=Tb=mI8i}dC$NXn|YfAh%>}%E`?nHr&zdjwyCG$*5dS} z3MBU;=x4OZ*#wpL>dv=)-k>hTy$drJ%0=D6epcO}=p959E(UVeGYt?0R%Ekt^~+2_ zXm*zS=T6xCBIh+|SLFO=@o_P@RjziNSgu?-xI&zUqse4I+6mQt-tHyeA^M2D{Ezkm zW_WRWvWrJ?L0A?*trz=o`Hj)*?i4c3&g;}|TofYKmBcc*&S|#!FjRS&P3?KR(E4WP z_7#S&f8KGab1G0iU4e~t@BF?iF|F%#VdY4arZ=ZO#p`e*zD){Z^efPf9J>{<<4jah zt4@nb8)*)Ien@+fE|yP*LD%!Uz%=`D)9Oc}#|xhBBO(P*To;&gwB!A;THJ-7C~yJG zdk$qMITnTw&l*ePNI4Z7=z@fxzk>%zC;TQh7}OB}yCW#ujlPm3#ZAM{5IHz&B9^~@ zg}Wstft_|_(nR_ZO#O|(L>Du*<6uUEuF0uS!}B;^HK z4bUJsN9+P@yrRleo#T9g2LLWR#g?xQjF#YuF1QWjOVdhGE1zePksGUC)t?c`Kvvnz zrGjW(AklwGRF8UvELAsz%3?qZO3>7!;jWTt6P)dpqpX zad3@Y!@l%nrgys(Pb!#ftT1CXW{D`UcM7w1wD z%b0C3=7n~*t7$Nsq^D+k48$eh&7&RKKepP8od58z&*aqcOy8f1w?Ikp_P5ASDBlTvi%b>2lVAtBDwjY@?``+t!zatLyLzaTw4aF4j!AhttoV^=Yp#4LNa?HbQpIXU_DNVW0u1 zN4QsTpb+*IRAzgRPp47WAVY`Aq9Cz0Uu9QSY4jsvUvi7TnT_=gO$xYd2 z$mhJL`nnF#e+a==c7whY4Bp(nA$tLL%|GX`22=dHR4D#sf>-YRrLQ~hhz(HTG()fl zy^p@PaldsFkPpniG0Oxb@c_=m6aQ!DuYk=!!21*?gj6S+=+Va#%eMAvX;dL?qVq$4 zn0sMn5=H8chJaL5MlUHKHi&(qv12N?57SnfbUFlslDpq_*~+Z=;^%(ahB+v)UQb6$pcJO&R+4nBl+CVKgRO4z}SBH_oua zjK|Mo(8oMhs?QQ}=f}{|;XA~Asp*u~ww8G&GZ`;}9cF^Yn#u7bAd+FJth$g3=+R@H zmi8TZ?l~P!2{TYjARX$TSp_V}*JrrTK30BQ#MAgp9u{&>5l|X>pP=m?S$C*|O!^06 zN@PZ|6!K$PL%D=)^RMHxsG}rGsEh(F8-!y=hN>#A`XE^325a!6t2Mabptmbf&~d$u zJszl*KoRI$xB!K*N_j>F?-fZc zo?R5z^H;cIUU;?R6KawMA>L1D!bynmtiA%!w7S)zZS{iXWjTx5xjobd6qQ6=rM+y( zs)c)~L^F>awN;>>H8#2*iJc=MO}e1Q^J-5^*`qHg-Eyada@o4K9%5MevcWl0`Xj~S z2=1X|zDj+3Z5#Hw~3+FuphO==8_(^pv>y=?cfb_eM)FfQ* z5Pt%$y1Ix!<@w$O>OiJY`fDD%MQBBS`g#99qM(2}iCI|Fx5vVLC?cGhJClk7qQdf}lwx@HqnAkYEA*=Rgohmr?P=o9{|m$N&7lfyfvfzmp_r{L|N8 zbq6%g=WsWkVQWnTq#7Gn+$8G+np=$=oXfQL9~{(A9TkL>;|OPzH%Qb&NC(l#yX5p#VZxXdS2ixTv^MB zN@<4nx6E#E;{fQ}=3j(i2OXtLiZ-?zb;?Dvv%n_grgVY9moN4Qj$HUFC_y&ds4hU$#!K z8`bm3`3OsHXO;UsqUU_qIf1(iov&!^Pr;*a3@vlH4ngfF2;a-gAkh1B)UES!8vJ5? zMlL(!tgA_{ca_V}&Nhv7?;bkb-vpeu_?wSq9={RRRPjQjpFJe-tgc z-v6a&~9Z@(Nl3 zv);SEm)^OjzQ4Q2+^abmde*h;jjtcq&E~W7OmYEz#7Iy$SUr9rf_6d(k`NECOP~-S zp_^dwURS^)I*QN0;=Ys?2El1@rG;_LJOe8mgM*8RMkaB0_pgGS-b83kPe?a8ZZBPL zZ=7^tyqa2NgqpMvB>>nVJ!I_Cm)QV7n8hyK=J#X!Q&8KlUq?-2HEP8dhgK6hF;b@{ zXAz%m-kr_{L@;y!EUDpU9FPPU<%WQ`aIanvFysTN&n*zswgD2%%PjSJ5W$E3>nQmA ztW9?xDDsn}j$tS6UGAY)roiL@`1>uXJ|T~_fHl++-qmO~e#-sbim3-;q!0-}2|9fD z5oB`v`1$_1J_K(E)L{(vUc)c`e?zqYF?PR~=l`aoS+L3b;>CQBVo&yih>_vqA`l1W zd6T8W8%`Ax@PZ3HO~ZOZuo8nD*lrm#k-gI6V6+Uo@Zehe>YyQT>hQIgI0K9bq7MTt z{Fu_O0Ii7N#~~tB-C3Sn{|WWkeE+o;`CfSnHm>ZzwXQCT`OKw}M5%>Up+!Fa!9 zonKa&J3Q#o=v-1Va0o@+luiEYkGQM>aPQT31N=cE_w;?X_Y1NA@wfMb*8dFhAX^Jl z-F?&o;obh)x<<(T9*KMU?-TLhj*1WhOH1nG8tmHpMXP)s`}o>u0g=(1qot>U{N{}O zPB-6O`X1R*8;>rlKpEYcsuzxcJk6qg{eK|x|AQ8PnS@?#Ju3!R0Rs|?`H&R51`G8< zgL?0CFEYWuDJEFDNW3`0Pekf_O2`GU`sIR6M45)V;Ji6twMt8oEkDP7xc;C7yPE(W z8Nvr4P(Yo5hd@BS)tS&25kHbeIOGuW(FvSm&{|Ly9}xnQLY?fPA2tvP6h!@ZFhS%?Nk0y~l|^97k=jl=NbdXRVNbt;w^}96kcK5n#%xpLi!2{s7O8Y^F)Y`V*@R4BB{`xu11;#kV&4qW&QFryLt`{TKL zAIQ}}M9FdY6%=*rH|1vlLMRF3A-atSM$*jKx?&`CD$?HjoHn{UaSLJuerbIxV-8ue z5$O5*%-V|pkan7DbTgDDN{^ME2l;Pt?nPW`6XBcQ`);`svWxfCy8m5Rsa1F~;8Q@O zzM5qase{kmjkZeeg+FFq+)Wz*Jvx6`3=j5yY=F3q&Tm9`T5j*rBYR#lK^ww%AAGCCqL*NSJg&KCj%I1AX`U zMT=%4oK@s-aUIBleN=D$KCB*Zgl16S==?Q;NEpDdSQya0q%IIH zsGWbP5De>_NFvBk859O}Y(jHwQe#+QZYg9U6p*BbG8fJqq|p0X3X zg$|*DfdZsJa93$uT4`K!E~{n`zM;tRpcHoO$>uugQx-m-U=5V5rxuuiM-mVpIe#w@ zieM!1aB#e&p9&KVlsF&+vCx0FSFC5y=dE`PvLIhpf(Pab;K7!RrGKPbtTPK$nqB`0vnce4X21vUVYq)>ux4t?fq8Oo!&K13m3}y1=|14%?lY3X@ zl(#70+xkfs8%gjK`#K(i&Mh`qiQS$u&JvwDA#!b=`(HyG=M|PK;SI3{UP$y^OW<@D$kBiPswLSEiMm7 zE`O@&^>q~7`584VRB3Ym8;9Aw)wzs>R4|iLRn zOGWD67ywAadgU-VFbIgB8ffp_-^5lz|FFaiG??#52vDM4S$$3`s+WhIB%LL5m*h+D zhG%2u$6;#V{57MYsl@43ABaFbKKpYg{;U?m1rAy9bNS`Y{*b3`{rkI6Tt7@5YI)iG z`vUJWjE5d-rSAVOD`*0u-+#5)Ief^wk`u2=hydusfjkU$GX@7nsM~56#~zI1i>$I& zQw5-_a?uW|8#>-!W;UmFX`eWaT>8!6U|I53%I6IhITp&2`jKy50R_ z?Y75MM_n|yCwbZ{KD7hOdp^9$k!ZLkj;!SIp?N%{uO=4Zaio4^Mo|+ytO~;s3Qe3- zUjTZXYdykHN9wSl6%kJx3s3ufkBw!A#g^kUU)^4Fee5cazkYi$8G6J>G5g>Ze21VZ zVJ0!9l|8lD`@L2jWzN4CY6FNskQKp)55R#zWksvB$^L_n&e;kZ$LHD+FwYXKQ7bPMj}g(3zaSK+4|J72(Gx+ zYRO>1?X)`t=$)Ddvb~KagnSBIiCv}fQO!2Ff5vQ)7X5InW78^iQ==-%C8tHiwo~vP z-|r+Xc)Q&{1Vw_izu~LKf1D3%lFtwR2H7lFM;U-MMvt7)skU5jdXCPtq)P&1%K@j{ zhpUsWk3-|_F-bJ|$p{~aam@>^*lSqtJ}x%qVo?08RP^I@Ri<%xSe29ibvLiYt|UCW zJY`u7GDr03eoEhQCyGjD7d6SPUWuG1t%K7j?!DDxqN)k2;7Rhvts9{2G<^h_R4XJ|m|9$)e^)`hd8tCI+@;Xvvb3hZ0J?q@P zAilUoA2YP{c;ZCr_7$k)6~)kH@MnjfSF|w(9=LTT#P<&>&1KtKOEofha7t*8S*$bl zid-KuL{MA(tquhprRTKj@AoPT3HE#g|LJ7g>fO7B6x9=gjuDKS04iVrQ38zb@`Pa` zh>8Ix?q&uGQOEx_P}{Pj^YbX^81Q@A^6~R{Ls|nk1oSBd+yzg(U9pHHXXEmC4uV?) zEk$_yStnfa;YJi|(W?;g=U+Y<{Pe-L4O|%B{QrKf#58dVcT&wjY%dU)eMI{f(|jyQ z^w(x>rLjn2oNR_|EP9=Q(E>^e|IkGto4@uPRKSU zXxbGPo`thh(hKFjAalyBlTxT~3ppeunB*7DaV1b!?=o7KD@y%j>o4mG_i-IeLeUOv zFM7E^INMA>4qW5m5|y*+(Ug2C4sGB+W)QdwXE8ZVcIDlgDZ z+n(8&%NCG0HDr0Op$OIQJ61He4+>3X-pgIO%Glhhvn2N$Y)!JAc}Ieh>WNhsCbwOp zP4an|%yaD4d)&C62_m02w!&v+t!Pg9#!jV4L8d~V165}Av2im}pU^jw+iDC-E03IB zasG}-qTDChNXYyQ=>ZZN2Nk|&Pe!&m*ts{?f8YeT?pbE7zW?PP7Q&~__Gvimq~d15jRV7p%FijK2K2%m;}m{_MBxY>38LyF6OtQbDhg zVG78i*FBV^wI`VU#{bodO?dud&QVbzxo^17LJLM+K{=N%bpfo7rZm8knC-+%fJ-0G zTqw<3E=HK^mbfDk@iB;FqfzpfdCpec1QjLfA6^Zx)ijfx4vF0eA*)bhbD1)OBCD4g z+3`e$AY4Vt+(8|mCB;6GO)09|he*Sv4UfKBq&u^GcP7j`VGB0t(zFdh_8EN&RMq?* zbN`0FD)RRx|+^4Tkd)53z zE(#fMxwec*$0p5{U6jY78}|012H5g&+=a(~=UB8lQI_wQ?G*+4aF`4dn zPl%77KpD$)C}+e>&=z(4_vKiI=YZGZVmkCYqM*Npseq@MO60RqMYc zMUHNu6F#`Xnd>9Wj(`vr@+}=k=x`b5@ju1H=}6Y7U#PHWh1x!>v9Bdem+)RmmJ#dR zo9`{=!MJN)Z5#HYPlD==YFf?F-D{m!(u7ijHYLmF#dB1W7Ze_Ao?9177vVEeYn=HS zhx^)R{MP`2^%vW!FWrYJzP>gw=Mtu%&X~TMzvQ-o#&$)LMwp=jghmv)wCT)>nv>;R zxgMUN=3O`*yE^VRuni%4fh9L9Fe|LHC5yD6csb~HFA`1Z4i<9?+BNpHxLP((j*aSqe=f-<} z-eaP9jyUis;GgO!Q%Il^@5Gl_sCb-D93|x%?#|r4Kuh#zv3bR)@)WBxI5W6WS0`iS zeD_x461W>oaG&n9xsq??lJCHNLQ9$dB~lp)0qYl~r&If5KnL|OhT|~A;(!%={Lni` zpc?}CnW$sG$I@I|Ux76&py(MtgOq#54uLL(n7t7BC@s7>c!GO!2!xdsRCM8VPws() zBZ1-q)APnS{O$_B6m=FopT4TLyOF$J_T?(I>4>crO^?W$f~N4o*T zY#vh%tB))*2>FPMr=PEh;tHQ`-NkOMT7&C4jI8j3)(chc3B~;G^X^k?xoLD!g}m>B zDHI1+n#M$rynkZ74NM8Hqp)ZER*4axs(HELLQLGUfD!Lcxbt@0GJv%(Q_4vQ>uAq& zvSu3>68VWcMXuO>d06>bZxR7~TjOASY6=6pB;0=)KW_>GdvQMHs+FT^d7KF8 z#lUP^^nAjQ3gC4OAf;LbDj8Z}cmLor@Q~NL+s;k~8Gm=|Rxga%k+h8c5tqk0ULb%6 zNo#49TztOZvKm>eX=F{sup++$M)>HaM4a1|-O+IKS!|#j9EpE)#sAXicrzM`JoAAo2L6q5Z`$`FiB7d^oSb11SxlcRy(EQoX7QKpn ze%zTSkgiI?o$xT%V$KB9C3LjksA!#x4X5G`$O*ja3Fd;P8^|Q8=PcYFrc1m05ID}w zJ#q!mrTO|HZo(P(aY63o8m($=fSe2nJ(RYSXNRyns*Psc|Ds%IW2$LNVt z|6o|`Fh;MX&0jz()xH6#LsmMQ^dZeL&e6}sE`Qag{^x_}`GkGC1x*K}5WX=7_d{`7 z^pjexG>~$=q@CMIq@I@o$@G1VvFLr;Z+^5W|5{XkUu5R3xr5{zdjQS2?;@`BP~?${ z76*yLn;+e#F8YPwF8-x`Dd9b7L$}@^{kNX;W=pQ8FP=oZosw3;ukg~$WCUz*Cqw8u z`+gFZb%LjK(GhKwTyF(vdaN8>S0Qwsh6BT#Jk{K!pYO%ox>mZzt@5!MM;G_5?4w=N zDfp>I^R}_=)Kuj;k@)hF3Y1Cdq|Y@@EGB~h5yqQR`@7!7Y1<$NLq`!Ze{-+##x8P; zC|*+)y}8J|*<(dPNceBkxafpY(N?7|FwId0Ut!8jlGh+t&d39xq1nl#Dpo8i_3R3b zZ}XYV@!{Fb;vN!ago^Ls+R0{6$#!jX*Z6*FkpSKtqcqIgiakBh$QWu%%1}&p9`Q68 zQtjaL_B0P>jRoIpYd8FKbLg(O-x`DiuR!1Xw`aud-!=Is^*1zoDI{n|3cgRqpNZw3 z^^i8p_Yxk9n#2^~2E zUDqzu9PXm{`YG!*NM;S4|?mzR-H@!Ouag_V)==CdT$03b7Snr zFc)n`iB=|<-N>Hp9p+!5lBwxeFA#!yl%mIi$M+++OZP5-k$mSmtU@_6)!w!Z2e9|PioE_0ki`;uRP2{I{Gi@*qYzPdfh)O`9 z7YQmIq)!N-3WWYm82Z=?+V+lFd?EA9AKlh3=8H<#Ukzq5U+8V`#LO%~v&Hu9?G+N; zl80vkuu{RhanyT{9%{8K%3unL+mwL zSmp16l!k1>^o>7a{e}V$npfAfYdi@!X8{4Gz5)_JzTrG1LTgaCqvraZb2qQDY6Ha% z)wt0+(e>buT$!M2k(LL^d_8T40Zy8&W^M-(f>zgWVi5;hkK2l($@h9T?67nBxU2CN zcRQ{A%v<*WufEh60rAU9`v+&LcOzobAnsFAuAeZ+n3Fqqf^);O>-{qlLPAB)GHav^ zC7&1Iee`Ao?WWsL8@CQHyqbd_UK;fIQEmycr@xpyIld~O zeC;iOf965Ti6A8I@%u7gPEMJD(X+A_`2QfOB|wRVIdo6oybk!!eDI-x{4*@ujBa{d zw)5pElp&m<;XM!e-CTjuz2N+hponq6d5~v@d-x410?s&Wxn{uUqzD87{~@X1$#D{^ zJClp6>$8iL9=pRLUUwh+7HjW^COm)(lTY|FeP+(@jK&Xejv!LBapM<~S&3`skW*Uc z261XR^3FW%=q8y&$pDD@2zh&>b4oWmqqwi(Egh(Y$L#S=yTOoiRatv=JiOs&wj8r< zyCTF)w3F%T@IS$Q)^nQ&Y1tO`CcV(vj`uc)XOHR0>MvpPN__5dBcFRSRRRFQqSIO9 zr7t=FtJK3!$zt@kdi{R$b+ou!&|#dWwi(PuIj)psI6Yb1?1X8gy6vsQ&~B%QRv|$B z=ES0_3+&>p7+yE6Y=+8;%S!L}aUk2}waVACT~CCssJ%XDOkMesX3AW(=3{?bOC|;{ zL02`!i8Fs0UsDI|AGeYgD!-9qe+ zG%B8SmF}l{cnAWT-zVk^o9!$mPu)dsU zs@za=T6NAy2*>;l`58bIe+P>}^w|XhWP}5@8*c|)e6U#v3u*h+=o;-uz|s$s`OyD0 zG$LR|3@B{AZ=9IJcP_PzR*HKiSI=NJ#iv@Ry_47g$rU0zk`CdQaO6Cfk_ryLL79*Y zf=LOPz%kulz3u!J>}L>+2r2$+KU*k>NBwANs)U_xh8+#a9P{2L!7IAFCBk_2mX1L;tqjDQP^}TEafLP_0hLXKnSB zVB-BMf+aOlNEoU1+!MEn?vlZe8*%t>A#@ay5v96Ja-+}5HzusANPKP~>gP2rp%x#+GRXap; zfKMOxEDNfx{06qaea3>?>o2`o!62kfr#pRuS7;Ct1#%1FPF~gGKB`>Xy*u-}o&B1L z=lu^?_Y_}8+<XPv$1VA=ESzsu(561wr$(ky!-Bc7I)|F+|8W%&-p&T zU%dqN!qu1uMpPMtg;K1EVm|`KRC{1pWEyq;0ll0UX*%obbMRY|OFC|3)rPHq9Xy&P z+es=Dn(H!TDwC}m4dpE6Ug70@EaUeE>vLqmxUT4oLg~#+^K#r~3l(9sez@pC=hiM) z=xrY8S$e9)t+t>mc8t;UJpZ|dtS{#O5K%+eBtuN!+g8QHh2sj-YYDf#X<>rjJWA9Z z0YBdZ`dGclt(EY!i1C&Q5C|@qsdQCf3Dly9R?w<@r2A7~D~I z;Oo^c@w#O$B?;=E(+Z70*1w4^(eGHe^?y!31u5bdi#+T$+AyrR4$_&lP$6wl>70F} z{5xa~#gt4!-Ae_oJb#IvR-n|O!v5^Mi3;-*!(_@MObBcSTeNy!nbF)Qajz~u4e zDI&Q!)>*7q&3cjxpj=`l)u1ifyv?oig_~(nD4t$OB z)g+kefOR(>Bvw~Z;o{J3n3gM%>5XwoRXSmQ-b?zyu3&26Gzc6T-e0==!XuC5k06KD zXjNNnTG|rBqBD4L|6EI@HIdvH-&Vua#t3g+1w0uUxaY?5e9fkR&|e>Xr!)? zk)rz&+>}6#e>q8|;%Gj{dI&S#m4v6KrImh8X>F329>#XGk|BoyV7zMHPB@rXcUk3M?N8?SN)h)BaUpX@Wj2|<3}}6n!sA(C z52+4@=F&vS>}Hi3&#a4%SV)FcoxaqpNS$6&_u^oYC#5h{#@@Lis}gHo>mK^rZQy{3 zE|n;SOJVYy#kOEneU~5oBWMP*{75o>WB&WkUi`ouO=`lHhae&rVA+bLRV1=4f=-4X z{^K?$i|>(8BaC9cbcR492{6DKPo5?Ii8WC4@igJ2(bV}XrZ<7(H=&q70j_0_Qht*| zbxzl{`t>z;poRf_-$24D%>jA*c>{O)B%~3f_+Pal$i9BvKL`pNDYQiYoQAGXy(&aI zMf5zpuCHJE!*|@`06D_ju(In&PS`oEZI{_ov9fhl$buHrxhaD8!f4|)sST5|Qeqp6 zP*?V(qkdYC6OD4(M4@joJ~B@#M&lPX+QnUVJO|+m1;3sRN;LC*r_ckAT_YTwUU15; zZN5Xaa7lVwTPa7@d^yyTGCFboHfAa*X@drVy!NoOi~E0iKu;!&;$w1ywqf0g&{327 zg317ynNt+ChPI$5UEXC!nwAoFRBzI|{zfW&c+_F9(l6X~uygiNb)35Nz)uU&kE)PG zvV$D4HrlhfuclspvW=-Wzi82Yd}48vhU4yge}@@Kw5*Ui=5C_QBVJF|dO>yumS-QA zBb1gP#j6P}AY@pKP%b>h_V8k!4t^tMB_3;QQgYwX{-h|_VLQ8J$5cX*UEtex)^T0r zs&^#`isIwyYvyZLwuR`gx|LO9zdC5g1%cHR0Kvd8)g?7VzhVr)94k-J+1gZ*SSZ`g zN2}Dt8W^;$L)WqvmM}zloR=9x%6y+43X4#Czn&4)JPOMz>43euqs4w$0G$O~t1k zdNnnEuce+)wZ=SfB&MQJN^+BosK!7NdJev=$OCOu;rIlkpP{kvZu}L@$B*Vn(JB!HJn=j z00y^`*JRa^dVwD~qF?y9cWRi4)Olat{x!kFbiji;KX!sTOg9oDX+cNXTo@%$=}5vp z0FO^!eOnf_!1hGXsJEmmeu$Bw;gFds8OjXpzp!h>#IVw;SmRiP>ooC^pchjP2XOdi&o`)0G z?~gmmhvirG%8=iTiI&;R!!*x~LvNl$;p6IhLWplUE`yt9jK)F!fU{N7G=zX*kp{e_ zw^jax$=}P8G4*W@h{eV;a-OW4CoB` zF&`v#pSv;Vdkiab)^XC>7n!{F({HflHrj~1o#6OZI}}K!sUH(0IsK&V%tYG%yw~iZ z`)N9-XT2?}8|jYL=N@tu9a(fPF8@%O78i)H!-j!$NVKKOZ0Ysvc6}|rzpbM;aB(^D zLAei2q)|33R(NWrXO9=7od**K9B1&zb}|^aCzUq3gX)DvMZoy2`_~NEO}RB+ge*#D zD`o%UaqE@O?BsopDyl|S|2sqS!+2-+r$*yV0+Bc!ZVQ_BIY0(mv}!~4eeqqfJy`-% z8YBZ5c5#BE!oIq@EofW)p?HC1`s~RG_UGvhRU2v8jW?6ud~dVlOqcZruw9Sx6`QN0 z-uh~^*PS7=(%#9<-EFrCj?0sFdy&!t*?EFL;eDuD1Q?P&Z4>V*rPo0Ee8axYL;3{z zZes*O{qpyE{bHz-@Tf1`Vms#Xd9CJ=nd(1brKjwIuO&pA(OH$+M6mLNeKz#C=P$sm z!;>v=T6GSuEA2S|=L-xVr&lYMYo0l@RnLZP8}E_wTQ^mRBaRu#@ZH&rO5?xY-Y~jC zvvLL;qQ`a+V*}hVyCfCZwfk%0v?q;Xr%dj=n=_xb`BTNn#k$|PH%+%Dld805q#MB?q&Hns1Q!#DUi1I!KPmWoqe|nUbE{%6#laUorxVUs1ijNY+)vZ{!P&+$n z8g&&VEKpo|9rwf93jW7Qp#g=*${E?czX_%Bk-ob?p}0qFYs;LQ$$B?4+IGGM?Z32%p?C2z0c_Iw3)LwL7gk! zIecK&J;4w8{5qT*(s7N42&dAhew_?tJ94gx`t}i{Pf*=HcS2TqF_vgkYR+UNe z$B=feqG1E+v4Dn$^ff5oKIP#eDV=p%ZPR6+w;hr~iCe@{KbjQ!xjIq*y-h{gDgI?l zOozPbc_Ipy7f-rY;(C5qy8P{a1DD$#sj^wW!g+u=Qe11_p=Q%5OV71&qtHlFqr@9E zOmCe8OQvYGe}#kJ1M;=PYq_vY{O3Oo3EY$Y9|HuxHhMfS(3LV+-q&qsl-l;5;$1E~ zxf;wb6EyPv;mMSho!+GvC5{alq=wCPaOcRL(lq|5){mHaLa@DHg?_FYLdS}@o2bfE zt$PE)+cPdlD|%qwByB=iRWgZEHSugWL_1tHc;%ECmb=UH9BX5yb}jNf&;~G9$k4?y zV^tvkhKnc+vyxYl<7pkRpTC{_k>nT5CqBOqcfVDiRBp)Vt8T$n$mv)0FUDUHb>W>Y zgB-uiqpZn7K5*1)EV;&&)-&uc;=Wz-3{M9%-s{K9^1E91_gT|xusBpLGVJVDomtV^ zfnqOUG`;4*M2~7b+59{wo_AqD9luBK2a4%ZX}`fD9{ctw?@LkL5u%nF_zc*PN$o2&dLsNDk!DIIKe+<6Xaw=tYK91gx;%iE#=w?il&!9!Wq* z>h#{68~1yZx9DGEg%gHgLvX>IFoA{zRZZIaB+Dl?_Zt0yI7xPX)(X-a!`_#5k}J5- z&g~?a5Y2CZzoslvZD}Mqp9b>a#n+5^KbPsJj^afpWaHK+|6sWxR1@S0NOqcc#F(&}?gEDnP z51ipX<6nBz!TiVHLEr{ixTT!N9ih4(CTty5%4dN^2dL3#+tjV!Bisuf-BqV7W)kG(nit&i3N5_{aeSjA8Elf^YaWL9U1Xuw6l5-f{CgE!?fsY?QXQ8^hGW zs->yO91?4sO1Q1x8@;rUG|a&e^MDJ^yg8+ljJ=Hu{bavI&CWwkOQX8ZGL=Y~UGSme zPlQH+XujXrS|I$Nhweq&VmL<5uODJpRc9m+ah0{?l6Rz8z5TZQ*WNJzAB%areto4m zag3vVsCG-(o;wVFeA=089cQy}C$^xi%UL@u8z_%-y`O?~N_aS2b{Uykg}+&G0dM&I z48&$Tx^~)W;z@N|T)Q9BH@MDxm)#ah5B3Qv<_nCBqRGI{C}mGw+w<_;$^y{WBj}5kGD-gi zUMHU=0P6)#+ng0hu<^+0Bc$hL`8^cm2=Q;>+ceKo$YqCz$7lQW=0AnBaN7@+Z-&NX zcB^Av(|Z=ZH#$_{%8SjYbjuE;xE>rJLYaB+rK6WddLBI%tbYiBCGGyDzo#t%J-Iw< zVuYBIqF@%}c%z3@6;k@coR=?<=|{%8^dzqFdlRiAEAK{f7eQ5um{6W|Ui3VHjt?od z3wOPK=|g`jl^Tb6dY$AnJ5#=68bPaVt02-2d(2qWciUo>XSi}k+<><*M}Eq?r}l)y z@4x*}hyAppd(sSK^sIp0Woi6|T5z*!9YHfG{-kUkP=@geAYDDpZj7UpOmuw23--0H zFEX=Kl!d)$3=GO$s4+!D@~jOv>UG#^+kcK#tB&0ULeiszSsiDtHraC1SKO-|AV=j) zipfgpm%DInI!!A=OKO^W26kh`1V_#H8Z*XWvW4*9w5TfuB{#k3U)tN&8XdH<94>_| zfn~u{O!Hv_)TQ#NwMz1Bt2+hJg|377C7Pls=L1azS8)vd>VO|~Zp>O(1C>$#+3=|f zF-=eqcHL|`Tcs@d<0US;>;5;opUf{z#7lE8lr{MG`zUfE{jZ+QMEKaf9aXpRkthNz zVXvbL?Lfo!lV4hITp;&TjYas-w#LH-7DeB02M9UEljVhG=faB2C%;&R!==aqm_IDT|J$s$Bk+1B&ElgU^U|h zB8K7#1$&B(A%*mo2Gj7hmhh2$@R7d_Ys=uUB*fc)ShcS9E13;Fr)T8e9&iQu_dEGh z$Sni+uoB%`?^4qbTCS>2`>?ZMHF$HLHoKIx({_g}Jl7chD79G$jhTEldi^t<1+|-R z_PQL+qvQG9rqtBZ$XX?#mwF5Kx|Q3*de7yL1p~_0)e)g$P>|t`B2uUE-F!z4eGVt| z`q*T$l=-Kw-gvNDas@N4zls~z&$-Np!p4Es%Z;FAZ%mGA4D(-^-pid}@%K&%d^b4t znSwi|Rez7CrhnG?McI{09=_PTMHp-6Cw)Zo_?|PDJAdZ@zr6p)=)_B<9*L;RgzuH# z@QK6n#OKhZ2f1Ryj=iHk;-PMu5n7t}7A7=6b?XOWvcE1}K3QQxt8>UK8hzNQHAV)c zEkY}Z3_Z2qWR=9}_0$nn7&W-FjX5*_L|>&*W2F&!K4MtP+Y2KAi$8 zz|yi$=&jF^6P)o%(ScISY?wnW!0<@z{SI}W0saGZ`|vZ$ph!;hId)V2?5Gj=t@qs9 z*rb-1qJihVz&DZkdfD}`d1_$x{HzY80j!?+3cE{BFN`mbE@m#y4kFvn%x?DDe70Zw zJL7){cvJ2FKm)bRYslo+$sJoH%`#+UC=o}YFJ0PgJGL>9grK&tAI+L=G%k`8<+*8a z^L8guEFCDInDG+rJpR`>drS+|s@;BgAfc!DV_P+{zfkLDkgNAVX=EVATP^0qz)z-d zt7Qhz%T%g-Pjp}0n2EPvLEg$H>&5SO=1)2qp5R)|X8P%M5(oN@=j+NpTimie!q-5Z zR-AycCs_7NnWGL3{S^wbQA-k&P@x%Nw;UfHN}L6s@0YwAIIZ>+@1qA03T<*uG08K5 zoXdSHjHz8*5D@mnd;A98PbAf6RIw`SjWJ1Z2^NJo(~Mkft6*?!D@b zHWu2+E{v0Jbdnzx9i2~EQ*g74rMy# zP!?a4k_4%s@4!uVEfIqCY!QHcv|(N~E-WJEh1H&DBv60sEZXa)zmXpQb;Sn6z7sh4 z1QPim5nQd~ZG%Js_{%rq9!8d%avX$}<&WqPALZw0^L9SL3iASUtOAt+g#y%HCZCwd zLIZ!|1YaCt!h9~_o9PiB)kk3Q763k5beAiS4JFe5_J1ivk z8a8p9?q|nfAnB7auV99EdXOl8YjP}`hOMr5=RYyVv=^TxUprpP8N9j*pBgBY5Uz7L zZ+HF&&z2kjliV`R-=B+ZY~{t;T6nff`Yu~>9zP$J8!9rX7q&*R8$8+H)YPxtkv9tP zpp+Fvws9oOmZkB`=|S6I8M1gtXD%#iP?y?*^H#iy5c4P0k!)Md_cJ;^4Unw%De7`m zd?0)p&P-+I*e@Kl-JIf4&*IBXkEwV11#U20bT_4SZl|o)%fD~6Kt~rIW6{eFM;5Y# z9q6EroFs9N<*JrT#XQNSG{Rtpvn2xTlLwAsk?jpABN5DPA0@wM1B|L;HoPNqH@;?l ztmL|*f_X}&%Y6bGIu|a&(H`oanuHiAi5a8Na<}8VP|ufDT!^9n2y+tu6tk!A$1rNq zhF5i<+xL*C!=OHj8{_eCAf@cuIr+Ip-Vi36|HtvL`fpouschJMQE4nJG}SF2_j^Of z;dh;Qi*jeYBO;piC5O1x%ila4IRYarsH_gnPh)!l5`368GSHB-LHc@%F-Koy(b zmJPRr5Ryr8<0qycrRH%wo$V`+#&fd|b7k4&NpK-Wujv5px)cTFI_D(m3H@JfX2hJY zf5sW^`79WcS%fbhe-c!E;OzmxOHbn^|5IS){1-^gS=fGy1rb3uX#M1DU;N-7A|fCs z%tZQpzw`j!da2k`qF&flG@)$?ok;eP&rLtU8=pUJQt9D@D8?Q&_H?398j6$-7ClRR zT{JDm8}lf9G+Na?=$ z-xP4(Nt#_o2Q&iENB$8`{<@I<}=hw#{Q58r}Hb4nuL$XYsK;AS(_Wwrd19j z*{$hF)jaNtvEkoMK|V3=W^%#3lOIP}?9;JKwnj)vqV7Q9X;)$%yoNDYW=T2q8tvlFm83Y$#Qq5T!+_jX zjc_Nfk;I|Gn+py{f$_$PUg~2?mWo8L>AMoLlLem04}{zk zO~PHeZ`9|5AlYMLb#QQ z-I5{aK2QG_{R<6{p*|p7lD+K@Y%LRS$at4+IF1ZX_mnQ{O|UHZdRlRj#^?{;)0x-V z?igC%Ls51hT}t%YKp%K&n~R53KOm*k$mf6RJ6G=%z=yHd(3TO^XTbp#>5YEJD8U#q z)d3z;@`=CZm&E#VsZRd6g45VhOgP4-G#h79UA}y15TuVFVq;I3bUQkJ>!A5 z25rq~VB4kIyV10TtZp4s;MCi)>w z*QF-#55fBw^vnv;@@XkHvNTM!)oECjfun;BV>x)!=OcY*HsT4l z7v4sSgaM5z!;K9Xy@aB>vrdOg!%9cTm62!jjgVk;YlT^}u~bE`7O9jXau=vm77C9B zqbA-FOsi0|n>VX_ zbGA^cVpHtg9N73-iO@wR0xAzWSh|wH`mM8sN=_vElC9dD5iujQid(Y5{CKXqP_`WI zr!~O4l`+~14J|=2y_yl11@$evi8Oi3w(>wxal`BI>Www%x1~@C$e`0L*Uy3PGMKP? zX?dU|gPK$|3!{PHia$jh%5LUxcvYvYCnM&zd1PU!94!WTXy$rVMr~}$2(Mj9@5rL8(A{wVMS_v> ztC)d$I#tJ&n2wZMgjpL#pM}ou+yVk^@^%t`7;_W`$AOm~>EaBaeFQ*Swa{1pAB1{A zr(l5qKNIQb!X6j=BQMI2NKzbHTnd(m;9njA#f)E_FA*s;MM#d{C&1|ww!t^)1uQ;x zOul|}jyhHFGPf@1)S6!2uUd|0<{D>0`w9~v!7+Hg!}_iToyFtqT^3`*iHt>x#AvK} zFRaRsd#ebmvh$g~Z(I-#O^d$usQQIX*w?lM@dawD0nd z_kZxs_#;2kD6oPV3s|(eAaHTK=5w88OctIEfu=AmZg#(VjE&w}zp?1sAHc6Sv>n1X>7CvT09iI)|pCr2a{ z{17%j@%BJQC(oms8J-*-{S+(iG&zQNdWCqp%*T2nUT@Rd0}?)DHgw~pKVbI&+ARc#t5===n z=xGqWdHmgCXYZ|iWDNR6H|rIFtZuq*=7)zq#Xo!fzr(or!2gxW1&3I#-8Vh&|cIPtoff#_}B@(`DC31;C<-iZjcjv;oMi!t&)USKl zg5bHXIlee2@oxEpe&}^xW%~WI#1MER6c54v+L8eK#^6W1B*0lxK&|Ra71(PI- zf8O)M_ia4+?;Fj^w^lu-*XUShxGMnYEUI%r+E)u>W z1A(9{{|T|c@bjY|frul0P=}}w4$wqM=E0i{@<(LRc})r(@)p?xR9nik@=YNongRmf z3Tj>K!^7Iu*JaoK=;Hig?`}1I_EJES<-a6V_KT!iX214Aow46#wD`=t`Wuh@m!$f0 z-Vl%@{)eP)>WrDofsv3P@#I`WfyFMzYaV9jt@^HQzKovQ?gK8tc7FFxk0cHdinv{E zz~>mXpu~g60b2l$m6%GFAuLbRxFa8j*9-c}W(_c8 zv|z-C{J0oNijG6?@bISI<VUFp3Cm5Xh`a|K4l{jAkSVKfwGgCNOwecPb2#mZ^a8@40W0yysUwF{%s7u6j!p zLv4?N7#xCAAS`MtW;b=|xw*xy`N_kBP#lEFk%*16p(8%GurZm~4@OU*a4S~PqM4JR z{k<*YUHwOUEZ>GWH^5%?jlC;yA~>EIf5OGlfYHw38mzhIh-#!3+K(NE0Z>4Ng(Up_XL47=3Z0K`|MSaH@K1zzSg6l_z}mJPj)Yu zmsju#_l{)pY})74AG_?MCo(Y}H6OKXJhAa4fi z`5msvKJMpCj3sq?v#UO}>*M+oysO}6(2U$U7wDtQ0oQeB z>zS~Gza$Y-T&OOPnKZ1On15pDRkt~8rqcy65U5U^UE8G(QVME6R{{O9hWKs9pxuk` zT?HN#Dm>+n*~`gMI&lFXgi{;KTeyafQvC}2_cL95^OSpB4JE^cgT1PwCc149a44!f zELf~>4?~nbm}gR=vT#^FC$DBn1AYeEK8q&^) zMEfZM1gxBp7&)~Pj6fYoq>z)q&#!B2Ha-F$=U{YjZj|Fq)$Jdn>1+EHK*XEouT7@S zhinuyl@FLUPCO2dxKC3NbTl-Fr-;ZyzJZw3PYK4)ezLkyc!L+%V(rG^lSw*`P8Cp$ z-0uvAM<9B=ZYORfj3X5vAAE6OUfg6cawd09440e;~-MtqVe+LH6NOsI5H+8nMHah`jvNJbk7<_eo8;+YihWz1usq#%EX)yaKh2Blf{B|?nZb6 ze2&NC)8$hC_-4#<#d6+Gwpia|qiqf|d3)QvRUkEd9xzJQFUkGHQY)Ngg}wCB_h7`e z>@-?2R^HnZ?TYwRZfk>DU`F}z5IAh5>|`vqcVc%=u?if?=-^txbzAJX6nHKcF$pP0 zv03jOX1bNvPnjEK4JnY1SYwJg`q62Rx$lLn5g7QDiRe_6KEN5vI8?~+uz+p;6Who+ zN9JZ}iT2pja{OGppRa=k3ET&_5S;ab4>1+Xu52zW+wP?5D7yWm{rd|E!dc(5Eui zh3?e@R8GybP_3RwKA1wXZ&AQyMlT{%P7cVitxR{eQV6h|P!ZJPliTQ@<&#t4>ysN_ ztL+oa-&xv8PVm^y1&3sUVx-Tr7vJc6B-GZ;yb|vP8}V zTONt-s*?o;M{T_p8w!JLdQ{C^ILit-`DKK2Bvw(K1Z`m>@e(R zovw!T@wt$Guav5Txu{7BuIbkq0^m^N>b@GuGl-WVBILSm0G5AW5KcOW7q;wXz|Wd} zPK#N4YUbfqknVc0H$PX+VAEc*gz6rcink6wMt&5sHZt&4i{StL*sKHO!W5qfycfHc zWpkM1Cx{%E2zy0p(ky@{rXXQ0_tS|kOix*3aO);}+G6LLu+M8asq~?<0r2l`VOQg!u(FFA`&z<}zsVu{cLOdw)>fR$(Jo=pKauaTyb-hNwGmnk-?%jks{k+6LN0U=K-j-irW*W{1$cgP zdYEVkpo8VxK?qP*`BQs?;52;pp1kPNy&|fkx+y$PTO8^U?Dil-1k<9*$Kf-2LLl35 zB%>fbDIkM)2Xz}@nW~peGSvLJaekF@ntiR#L$qBXU2kO>6`zLY7Mgqbp@hy~f=VFZ z6g!AK{III3&EL)djF^TSJts5s42_RYa}Qm96;uTT39Ch&G0WF^Obw}@G;1#D^(H4z zD#P+I`RPuqujkHAz0_2k=W9HIu3JTKtVky{v0&i^#W=vKyrwn zy#<7NaJs%qgzUFDWU#rSzD3)gNzHeFnZ6w;&TBs=y!JUy`kNXYJe*nrd>tvW0m_JH z4=gN5R#SErg&(TkW>yXy{}NV<8`m}F)2iD`6$S?(_&QGdjeK4=2rTv-MoJ(5nd8wI zuuDI-moT=ia>V{Tm8zRuTKK8SwX-#`wHMKu_(ZSLLLdZ&BrJYbDUWPc>qYydW@{J^O4^mx6SN)2*&ztXOGJs<2j7@TSCJ90R64F zwgt2keN$kgLF)mw$vHC`*(km(6Ym#FhDej}& zI#%Wp$(AaDE`Yv4EWa$9lI~Q$A{PaF$z7|d8Kj!M2pXn`yC@ZtK=#k7~>ak{N0AkbG% zgVtBy@4eI~i=`s5?)^iBn(UIi^{N?T*LX~ttiXR+D)|TT!Cq{vu@cxrwb^ta8a#I9 z@|Dd%spfoL`SP$eBOe0vfQ&)z3G>?oO)~E-YrLk%YNT$yaardO{;mjD+`vGCg4$CU zbvZVyq$qc$YwEoPouT{1PQ};t{{y#q`(FYie#^k4h^!-t+SrWx&_ZeIO42VmYwjMe zsj7SMh=1F14@_x-5i z+6Ja_{>`qth$W^)OZ&gLQC|XY{Qvn^DgG36ejr}`MNzm2NrP+a!O1*9vw$m;O^R-S zf-Dl-_bRVRRMAKlZ5yMdx%=91rV3S`bMx<4M>K1FnQFr@mbxLL5sRJ~3dRJ+hk1FX zrjR*gbweXpEhqb#l8`Nd5YQR`VfCi8iyr=j}0i|HV@kk^ZYw zow|wLZ~hQRUC^%ZBG9f_gIadoOyy`l{zs?U{7;=)l)Z9`^v@6iWW!|;X(Cfdk3_W4 zpA5ly?-Fg%Wf&?Xt^?`MOXWkNJ4Mt9cb{>7kBoBreijeF^;u9}Q5Bw2{@$yVJKgZn zb*^!|P9DAKkWp2O6v?t$%*6%4BX?cyzmSmyZy;i*6GSerXO4r+6gO zDKfOQrp=b4fAxlFMtsgZgEMYf9Yk*&)%X`3i0609z6uzMktH&%B{eWoL)dW;MNF6L zk~hF}-1(#udyZKk?mI-s00*1&zSdUu}o)a+{7jm~{W2C!c zduym=(7B}e6)}5-ySO8=Zfs6Y2h~;VunB|KD$&+%C|oG&nU47oT|PXF6dqH-4LKfI z-XzshAxwE1|6eD(P6(lVdgw$G{%jPX<$A!53CdZS*Ko2{__=enmN*22Bmg9!DLXqG zIwVb~%UcN=_Z?sK{)?xo(uc94Tf~+<6~ej?a>~{tMdpY)tJGFi2aod9fwy>wNPqEE zJaQAAhPBv#4L@Hjif_A~g-d)ZpGU7y4_X_4Y3C>}!JN>=B7TF}ApNIa2k)@Rp9{>% z<5d1ZNi)c$zVeE=hE&Z1TA;!*$BSfqg^I&WdzJ&GOv*Hos>%F8~Whr@f36 zpS=f9fiKHdq!HR>)aslw%7YmZwFfwbL(TN;VUc`vcqwoi95@Qds>^Y1jR`Q}DO2xG%-XwG=S@tG)>tziJJ0s!rGs49 zUGuF<7GfE?MoGGlk~4DMMc9Bq{Dr$qa}zdMrLhe1Awfxr>f+dVZFtTmQY~UOQ6kI# z52#bTP5F1amz3X;`E!}YbQh4(9z%+z`z^Y+l5hP!VRo|D`a5CP(E!no!raJzH1Twk zIiogHa_FB>%X%f8wONckFbwQsckx1k+Mp0{pDp&Rje;*KY|iSL9dWDVbe=AyE{93R z{YK{G62DOfF}z1&`apZ4d3@&;^#RQe{$%ZJ8-- zCer>Sl`y98mU2pYbvR(d9NAR*Z*sj|Gy1_@W~c;GfZROOEeCqTqXxSJmJND~q4}1@ zg;?k1Bk0uOYdd`R6#w^Wb7T~pecjN0{q#b7Y^;U^erl`~YUNXv7t4bVvs0peT~9eZ z1gCvn_4m`K3k6(-I@r1wP;?P)jLYTc>)TAY`?&pn_yRS_5=x-fwZeNmE8C5f@{gMP zM?l1_eMUiwoS$R7c^ZtS#8kQO>j$^yUvb;G8<1?NCMqK#7xc-y;`BLi;YlkffOW&d zTDij+7H*Sm&^k(me=^f`ElE=z)k%0zqVpP>>^rGh8>jV*M9-Sg1vy>a8cyU6R;o^x zI=oy9b$m%uyERaBrV~-WFpP&c16Rh(*jMiCPZgLo(Rh2c+Ha{5>yqTWdTgDniiik> zK8qjSX_0MJiW@^Ibd+Ij<6oZ(D^!e0X-NNkMmGmxP;cj09_Wp$))VqdqFQCp|M=n_G&4hlLc7-}oKw7dFN{iah}*zm?X79H;=WOEho!HlbhlJO6M)Lblw ztDp_SjQjP!aJr|)1UiJKwo2|Yigh-oWu#GR834AKbt*O|_4}F|jG9NS7cnRACFxp2QskRt?c3mD*L^t~TFtpk~L z8c^3=dVsCAr!-mBziH~%Dj0BznLUh84R1YH34wj?Apk|_a zzq%nY<`#z70Ov`j*L>#XjFLo_k!WA&k9S#$t;3C!_|d6{_tvr7l}0XYv+xfKYc_TW zuFnDI!b3m4G(>k4BlvEFdvE^IwS`NmETEitDmkqk$2Nfy|QZB$uK_IfcxH z+a#lj5%~-1nPNn#t*aF&M#QK+s_-(dkv+s~{S_h%T19DlQ0(t!QsB&qZY zxv%@*G6l(7kB;cRZY#^9d_#?~`{PV?0-BQi&Io!fcA}|yX24`*_z(FOCBTfos43%} zsBBGe|IBSNnp6<=mOa`@LC1m2{E@w_k94SVE`RvZXfG0JQqgBqf~K%el)^&&H05>1 zJ{MM&d4Ghin~<=`TzcP1W2*-FWM0V|>3*=rq8X7sXyi|1!Dia;3Det|30NIeX-YFI z?s&vYZYQ+f9JgN1-|7LwqClTZaLc8NvLP|OeQC(AOFEyOho@_2u(=2d8!3kIJ9073 zMy`~+h>gj6bg{2WX%w9bgxQN98G~q7$Fr1>V3 zU*4MLryp~a!0>oKyme7ckq0M%nIPpOK>|d(i6cbqRH?{a9C9~k6>vWJl__Q2dw&Cq zk&U7`k%W4vc+1qLh7P&pybu&xt%rs%JA#D`6%P?l0e|?yp;Z^O^@5CM9g7Si-=2J* zI_dpOt~NC)t#3oUD<=QysAt50ErGEAON>I1{Rl3bxula$acbkxAhOoLOIg;%lmwEh zQ1v#l>3O@~qGqOph=cI|jCE(L4_sGZmthgn%7$+yg>C_%|0RXv2t0TWxEx#~<*b%8rsQceC) zxsdb{Imu)x9w+)IK`$rM4DLvd^u3ur!)hV#v8vlk1tt;+zI{;&x9)3mxK2YIiK*GL zztL&b$J?MP-4pR~(D~AY&1~uR4);A#&ow;Bg@Iy!Z=Fa^#AS;4?bJ$0IK0hVxbai) zD6CELkzDB>fH2LFl^1DH%yx$YV3HZW0Fo$p$O>+RtDd1dthSkSr4hlx^YDzK4qa2T zTQhnfur(V_O{qV=adk%avFrr15>|+yZkE|4fi%*gZZ?JS7yLVXot&39)}hZ1A-C*V zTCrK9Y3;j`{MIT9M@qzr@m-ql^?W`Xnoc<70DxC$|q*5 z3F~ywKl(>v1yv1QA>r-31+#mtlVsJ_o}gF)9=!<7-^7YWm@RbrcGM(|XAr=y!ck2T zh*A;hUmveJaqh5xliV)4Gq{h(4GJA6aFFT^->`gcnb8Ha*Pc9Zf0VA(La8?P>Gn`B zp_0B0*~4j>SzfUm+rZAi;rV@m%&|2-(TI6*I^i96PQ7d`+(EpJ8W(?he>mezgQu=C zwKh9)Z|Re?|5vN=z}t-+Qb1qX50>*B5Fj)R4`a2%$jp>4U)px&GqJudWxnD62lH58 z9g{tUXif7?6tdIYFgVLN`y0ihF~Q3~EIKU&{|*O1^=87B?%&@(O{V_`Tldr*R-mwJ zJB@8MwvEQN+1P0s+nlj&+g4-SMq}G(j4$h5``cq5yoYnlA24}87e_1>B$=ot{K7tj znCK(sZ_hK9`%N%p)DL<5tr(PEDAi?Fj~S>|?ZxR%k?kMkK zT|3k+e3njx{SkD;p(7Av{cCVn;uq@?G92?+{GQ`;k-HBYbx_a+)lzmAiT9bhw`CIL z?K#Ac^rLZ=xvT}0gGOE!SOuM3{WGbWnC}95+lSf&Wz}#R215>Qi4IP`90o6*f9-N% zNFF!Fdz~lDUs4dC8I?Fx(Rg41)7(p^-EgY!2Cl&mWpY)-{1p``*p>-8L2{D~Xog@{ z=vx*%V`!_tN04nGS%BjZkmNZn)HH* z7+JZ}T>?MfTX(@P1f@wCa-6C|dAWaL4r+>pjLd-4kY3cFKl(Ht`+efap${-Z<~&$aKOkVf^G*bJj@mC77C!||sD%JgbZ9o)(yd9-Ju+*S#Vv|9(6gHTi+(@w)ZrbNZbb@?gutr~QHRgMMTGV%5$QvGr1jT+OJ>nv z%TcR>sU~L-3d8%qU*?-xZRrn@;9ss_c{0nMkaV|<;*TjmRSwO?+-XT5{HErB8_P{( ztl$;Hdh_p+{<4(A)XrpDt0Hr=W8F&JS?2IT^7*_7Kj2ofES&-7gfl6S7`LE7?|twi zQkSrE8~2!Pu{pY9=;P!PB~jUA2<62Ak)rw`*mO9#*`Zv)L{yhGntE8p=c(gPc~ki1 zXnJsEBqIxHb#23&@+v`M*JbJGA%|ypw$M@TT|U-vPW#tVJfv*5C>`%g?k*>3G`GEU zx9G@x4UmcWUBa!%L?OAuxr=hEMupKeDe0$8sb6NnCya6Jenlp(V_#RwaI1V5>LV>< z@M+@+0a90<`<|nz#W5}~E^(OSZ7=bzj3#4t{S}i#4DVk(uMC^JG*gndENK@I#(5OI zYIEB$MT%9<*|pJ_qb()V)PGNv5r2wAvKtgn@PKElGvTDG^{0j7>iyZ&@_XKFjX z_=3cfP%Td#qmJZKsoRaFJ_%fkgh}ii#cA*yvw26B08R;%I=B!Ws+9zG3v6(<460^!nc;mT%-^XmIvnb7SLw_k=hwHfl<|ap&4xEUN>ISS%w72w$W5D6{D6{rfIVq*(*Okkf z)e*EY>^KWNcr`IZJjcS}ChZN+SlE+Q0oM8p7@S_XMV~43r%W3u|B3aQGWF)QD$b{(_OYdbhYd(KinToZ_cI5#3duOXV0-;Vx0K3x9LptoJdf{;2^IR zB6)RQ+dXlES%j)jBKw8N7EuJKUCC1nP!Kd}(0$UdtX*HEg=8mvb|Fq>8PA z&t3kK!;oj1wbIb@$gH zB3|t->OJz$O#9#VU1Tr}PMtH8l1#<4Vw zf=&8!U<6d#_X?9A_`KN8!s7CahlYvO`fM;f6=@d`68#VSYHecntMgOv@4dTYg27Yj zQ23L@XMvoMwJbacX*r~AXf93peC6sP`Kdo&Hkr|6yqZOJSwa12hD3U4exkE$z1C@gDQN$o zm*)z9s=flASI#+q`^2r8>f^%m1RU1tnfC3XSznHc{H+R2gBKqByFB3uM*h|c| z;7N(%z%n<`X=*RB7fqox#k%EIMQ&02#AP^U44y|MxU(2v!c9eE$W|DuraAT&OHKx`_rJ>}Gl`XSSb#V4A&z(;) z&}}tujmfB8j9LxS*R?|}Iyel|mTSJ^4KGAM-sb`CymF8x^F+hN&^_*D3;OU>p}Wz*Vh$QSD6ksCAQZZ3Yj5>PgN_W~{=KP#^X!gYSH40T*~X*Ol_wQLJAemBOeL@-ig4b=>SN)6IKS-0B6j`O(uct9Ph zL>~G-d1wG;DkIekSfeO1v{0OFZqaoEa-kWq?a)8V82*GxZq_W0HWq@LC2czH242E*dofg{H|f<>uE- z0*>iLON~eOE1N?*%$>wGjtNUL%)Nwa$ZT3D9=*mT)7er;d;-l6Cwosba&u;X!mnYO z>3gAIFrU9%TByn46SznWs}HFS?nd!nds_dHE( z-UY0^NjEzq-asE#jF^AV{DausehDevJ8D^3Q^yJB$YkHL+<6o_@SmB^~EI`yYm4gCA_TD97PAmTlKq0r)J@vQr*ag z)nIDFy5ri`3>Bg%P~Zrx@IOxf*m&q z{g!%V9Q>bw#eMSw^MTS&l?g=*{?x!%$Lni!-fLwsasuJL&d2&sWH>n_!@R@KZn6@&`_wwB8AfRMfT>P&~H_0eQo zuk-JZv(eg?8dGXX;!2yhmL_w3n!)Od^1R^7_ZYVcVDp5k-sT6i40E@e?K!`_-`Tp@Y&jD_MdIB z1!h;Bs43I{Er~zwla@|ou6urKbKVhmUg^N7 z4#ak%{>1+ZME%HvEe!ttvt2{6hmUg}RovOSR;u*$oeZVBK2GvJe)XT3X1>BVR;Wdh zEf|fGZZ8n7M;0{v`U6(>4D7A1e3;k!qhNmySh+a*{UR*d(7n41%xtbmFf$AFUQq>q z{8dH1K^Q~?I>D0#+#(`GqO0}}Y(t#xHa(%59`&$fhPSpDMlRRH;dmV&O`woC2n8s8 zYzyHc!d-n+_BK5?z*d0s;V0Ms^r02MnzH%y@}?F`G7p$os3TJ7sMok$#^)z8!PS77 z{Wu=W;~t%i9+rK}PdY13xstIiqPe?P!+sI{W?Phb`ahWKU*VGMaJs%7X%XfwYHyN;8O3EE4&*bl4VG#>WH1%5t^QZ}n| zvzXJbUP8yKvYU_WHUMX5m*-+;=z;P4n#ohN%;<%GDx-k@6jl!y5 z>9wSJ72MaQO5q&s#=Ee?G&2JABit=-iJDZ(AT#*$1Aph}qQgir%Da5T@_SAGBwzXE z=&@G#csYNs%oVWDRr+izj4|FV=KoZDEIa(`mAYWQSBi@CR!Jqv@iDTfknnh?g!_ET z|3d6LZ8u*sa)}-7**?ipb-2`2sa3VB6!@+=YY=XV75m5o_FCauoIYH-K&rM)ZC=4y1`E%z5$Y7 z4F>7%;m*yh^@)cvJO5&!_9;kWCtpy)#wqfsc*7_g^a+L|Fd0zm)ier?>& z5xUrlIOs0P!X5=)p`d|WpB`i?CVTXKR~SZ)K{PXo%o5Crf_7{+28NS`{K;S0f(~6( zbkC>7i1GXHS?jVm>&%_Aiz~FQW393b?XOv&kzqGzR|}~jZNv#<0t`$GYqeJNTQMG* z!Z>r+FaUS)HZ$)VOXG*u8_~O!c8sxE);osMZV9nbV;$2=mS9zvX(()ry6Rpl{liR#!}1Xa(__97_sr(9 zO-Ai#Jqjwx$P3s!qL^Zjm)e@{-*At+;gKhW-{s5$D%iQ>>E!W?a;3eutU|=(D zvpq4Wl}f6bTg1Y_RKUn9a#Xj_Xb)~xZ$x)Pi7d9k$EJ4^(~={@rVWw)I%V+x)rRHWE0?2KVdA(+fX4dVKY$D1t-s0@Ey)2qQ0BG{g=Y&Yw_7G;0B zW5${$u>dTljgJ^{rnGgM;fs|-b8A_I&X^H82Wig*pewtfo^!fdFW!-S94+tWIhv21 zTMWoRl!7_Wy|*tL9=BA%=OWgB?7rcD{|rzcKvt3iS`wsu0hTjHci#8 zC(0Ywd#>VGI2Sp1`jIrViRqluS5{QI0>HCw3DoI~}*N68>hE`z4ybp*e+`Nus?8bd~$d?0H$4q2sPfL)Y68bguD$77rZYpj3UA-?ua(}0z^7;NPe-0}|dvq~A zQ)HRsoPdfk-gGjU)iy~A?OU4>cyq}()livj7*gd-2}FT|x4`~IJa#UFf{-C8AFGBG zW0}JJ6iQv^z@C!4G z*6~2gSa)05ts0+?Jr6PJy-wunX~5ty@Kl?*zKF5O4bG&&*cv}W)7sO}qP|xfQ<3G@ zj+omlMRSM6o&AEZISq{scG@(N3+lDW{-BZX39`v{>!bUq6Lu6)l;@b_3rE<$17LSt z-sTr&+j=xYB{>a0i<7pg#0O2VXd^?N@M+4|6XT3xgidi(@tXapSpNwnbAieqrsf3M zuz5z+f6{l(DGlicbSg`08NV)|I=|Et=jM7pgVnsV)Ccxab+hhh9kh$~JpWQJ(hMd964tf%3@(}V9sW&DG zMf!-4hJQbz6W%=p(gM%lmAP}i&#&BZ&*@2YSum~Xsjg!X{}H-I4rNQ6nel#^#6!8U zq~bL#bY9K2Xwb_ld&ViTz1>S^k+F{1P(}3dA<$~^1*u=x?W&iwi?(ys0{&?-^w4=} z9*KI)tU8H`!-~%c7F7?v-q|ih21Dv@daEA(i2YtPGg7S`Tu5jefz+1kdgYDZpFaeB z)rp(guWJQc=!T6rT@!eAeNC#;L`tQ!ykKH$X(R&ABfF&*B8TRX_QL z-+nDLsZ<%TvLuMDbW~RtKm7CuqU#HxlI9IWrGA)RQ%}$%D2-1pcv?`lHwZg%{gv3b z+w#==*zHNepj52fxcjLC($D&tN3Nfrm3dlK4&`zVRvBo_YN4x&21GZGY9WC(^eJi+ zO4=~}TVx4-cG|4 z<&R~^5*{>f@ZlM)<}R^zoWbx2DWUDpG>YQ>?Btd@!9s3QSFKPV()a%0E{CwW4Eyo> z{upWLLqO3O66wEf=uf%-0HxyGV!Ja4uQMCeMASskl0e9Qp2#i{kv|bC$s9?jFDNPv zIdr)491$i$zJETExcf9*Pe?Ap00b{PRh7!ZmMIcS2l#Y7<%^F@$t%6~XZ9E8*o%Ky95w zuGa?26mSWRp(_%Y5t7vjf`anx%Y}Do>W``V`L6N+rfI2hT9&2%*{Oe}x|X%&NZoF~ zmE{Cxs!b{T?5%mP`bCtQaSoKVhS>^O!}R$R1)?~fi~553CtT|E=e<4}5c$4AZ}EW0 znsy_8dp%0rwL$W(dEE=XH*Lz^F2eW7rLWx}2cD*HB8GjE2hnb~BtWTnED0^4MZrGy zRuIQp9?f7u+XsnuQo#qV-2Dy+pmRHvnqoUmK_1+QKgN)5L;klu6yUp9n_yz1GO{wi z-LPYdfrh^^kR;whfVyL%ARfw=P&^L~a8LB?g1`v>I(-FTXrLI=>|F*qG3h}Bn;PVj z1qcrG+M&Xu7*K)qBV$wbHre;;6EGe7_Cmp@^x6@^Z;deNeYBAh`MUXF5BwbJU78)8U0nBF#coNTzkTCTR}XFLjG>`W81A1Ua9AZcu(_h4 zBfD0i!JY-09yaBk%0^;T!7NQ}Jr_Z=J-^5{q({OaA1RJEYh!^ToR6lu9Od2-`^PNP zy5`p@?a7tJ;g2Jn&-$6I<&P9{B4n)zH<*y1Pwr%R_@D5U^ta*`64&2Jilp~93kzxt zHg5zx(6U{AU=y5>I4Sz;XNJUJ>#^&Gm7g9bds*$N7 z`{`jn6t$kAHP0<1M~jk7jNx!zO7+6c4`}T&ZT}?XZ@=k8 zK1=@>GxpONe53Bb{IMwrsaV8SuDH8!FJP#1DEk5(>63OCxdj?hYFXt2#ax_c7D9hT)8k#+|8a~+`>_Ya7IVJipbGlOn_CL(2V8?%$ zQ^4;pbrh(KarKfxIIG(cVlS@%^@wG+H3pO0)q*qR_y<+cO_iHJvj`JmKLTkp;{arb z%D1A~p(imSE2t;zfNu~EFG_?k(hRj|fkZ|;%oBX5`#liMD<|K`V@ZpfHssr|Q)AX) zQngTd4qAoyjgWMKN`U6gxOqd z+ASu9Q)uZcuw-h;qUR%TN{~Y;|4g0UEkd0RSEC0W)LbH;ZHzl! zFsFiqJP`rYXjLek(%^$Z2l+A2{!)5OROnLR$h+G);Y+@&{dES4+hmB}7!lFo!ZAYt zp*n|{Z>u1ae(0zmgor`=MhE?U#2~0d+=^(p{z0L?w(I>mUX6&0D2gs~e$G(iHY|*w zVBSgh@SlXI@=K{Oq|cxT8qChH&|T3^7?fiUy$? ziTEm#5&On~2}B2peB-eREd&{1Lg9r4K+!C1DNS7^2$5XLs0AaX28w#vYnvVK?3zVb zK<`u0L1Ag|O|=t4nnMDRgjc{0PW#kL_rqsY)I_2E zkYJeRkYQj*zZH@xE2D>@vw#(l7^qq?!alue@2`#jPg06t!u9t*N$IR2DsU|)0%KrC zg|58X9W1AwN0qR-$Y+h~3a*T)LP_a;%(h&Dr*K;o6SK8f0H%?e!&)Qr_uz3m|A&`y zv86<38UFBGZFXgKiHbvsiIg0?Ou_G~G~XW8tZPOzO_fE(oWQMr`fuA=B-t1Cdf|Yp+XLm zUG9ke<39X5wmSM~k0T9{bRz|8GUu*C1T!Z=m2IZAb?3IF4<<&Yk&GQ~3eC4dnLXBA zvem~qiR#x-Q({mKaVvuhLx9FIf8N_1mQ~e4oD1SyN;u0QF zoDy%|&kqd40|8<1J`t`5{DB;d2a{g#-J5NESJ3{t$J5G6hZE1B2c2jre<;6knX0>& zj-%A7JKqk9`Iu-<8B+tU)Tn;6b{`}Slv>c}^8opyB1Hm0(df30x+e}yGBoTq98^+C z>PDAYgV`uhWy(qe0$8pSlr2#lE*D^Zt%aSWO9mZE1(nrk^F_=}sz|FKs5;%>+oL9@ zGK+A)uv@d0=~?QRo4IRbrT966c3^m9dA3In9S(|UVE5!tx(v(e@chl*M^F}o4m|Zj zfCfE0C~ZOFaSwz}%ccef06w?a4P#yy-CsdMm{?Q<^VT$&0Fc}9{UGDuT@}9&X;zPk zXleXu^&!)_AqAKS@kbK9=~b&ECKQ16KE9h+at2%S#&3{puzBW?6En{3*B#mUyU8$*3`e~GZ;Fl4n2R+8J z-6#77X=a_zfIt`_Tbg*wyns)wb7mV`YW?}vJmus`rj>pK+5CW6*p>S*xVc3N1$wLS zJ}ev7yGkvtaBfDbU`{;xw#VA1`Peui2Z>HvPuo=$m z+*Q_%pYGsGA@Gf^jjV6#a#;44Tlvy~AO`A5cAq00*ViC$epgE?y(>$r!vuN9XM6j8 z4i7MI)%QIWoJ17hp&*j>k#lGpQQ=1UpL^2JR|{Lbby<43#?EK^6#Sw*JVj26e^08$ zBo#8s0Gk`FhSpu9(buNtwReqW_Nw`)sD6pt;cbu z0CPiS>OT(hpY2>BtcXfGDqGxm%LGeisA2O5)mKYn6bEk^P z0~zTWYp)Fv+&I-5;*3wC@jW_1AEfshD+{j6fICMFP4{wJ?X=Xl-Q%4O_erzpcwAqs z$^D6;Bwj&*{T~~7vqCs}jM%z&FSPkN+P@Y)e9Y8S0R-Hq7N$ApNZ=;a*(c&V?S}Fj z0c&!IVx z&OVk~0t%?0a~vCUDnB&x3Ww0_EjiXxfcd#b&I)U_T4$HAq#nUFXvmlY@pxG;%*m9jeRb@`mgYK1>_@cA|%R@c9 z*d36@2evBbW=1nMC3=-3@M{LMbG%pb?3&nzrkj@7spv`Ue>o`5=-cQV$4ln~Hx7E` zzP69S>yOm&=!15Yy8rr(x;S?qPsRK}^C`R-LI6yCSjZgx1GS(tL&+#` zjfu9Iq_x@`7pk~}{p1;VcouFoJ$SFAzV5cFdz#bQoW3i%7*mW8+u$O$7wrS~uDu)JICpdx| zojl-C%hbQ)2LjZbwUw}YX&(R z!X||YlMhh;O3Z(DaFKuGNZpVr0v|T{y*+EW6v?*rgG}oL)mKd#B;^T&)9N#1@n5&j z5g`+y11W*w!qleVPzWg!KAV`Jl+OTk+(1vS4vpZogcv|a28RjSeN0{vB=EiynAwvQ zOuKJ$v^I^Z;>^A4p*#&o_S-2>(D|m|g_x|A!C|FO)2F@p-#nrcfeh!a{*>L+r{fWN0l%dA%a|&mw_w^3L)1>B*aNoLk4s6Wmhmpi&v4(o=*W|77 zSun@_ASauyoW_SqT~6`z^ZS+3)W~T#gjGOIJpwm z{2zv2C+1e4p3RNQn8O8@Tx4hG&V;+A@ulu@u$hbv1gcgrnkJeF%O)%>{A-0BKAXr= zfSZoZwWd`Ngx+xHBq_d#MrpBq?$|{U`qxJ7Vh3Q< z^S6gjP@uTMsRw^fQS-iK@WO|7XXT8;U3ep<)mgStPXtwNh@8+qr1A;44{I1-I3SVc zXE%9T!E~sqgGmcf>j9l%!|HbB#zPd#H}C6hjLkV$#^GQZ{r<(AO8NYUIsLwkeA)d= z8JOV|6T#^1N`hb|>s9I+emRE${f~2ca_0!Cpf_}nuLrkeVW&`h$0S@=&+pEhRVU;U z$a|;Eg#|zC)Bn*q2TLD>Oho3dc?SYQL_tCaB0dRHX@`C9Xd`MXB+7w2dt;j>a}IJ= zEhY3xsy{nP08u@K+?M^&Uepnn3G!+KFpIm2d@-l$Jb`g}#KMc$sfjH(AV$fhG(9yW z)FfTgNItPSaSa)K-FY#8GAR3I2o8>{EOR0#JmGTfQ9y8TuR_ESb$4M5If?oDRfAU= zLKxoLOUd3)nQ1Mq=n)1+u?+ZYjk0~7GKt=np2x!>ZrV>r<)7zJ(IHlo zI?9Ze8N*@9Q?$mTj7h)>#6ojxhH7uPI^$g@H=pnFEFv+=*N^UIA-p{@_-v7rwL3*u zb00(IJGexijSKxk?*5<`1>Nq&!rItNtgd^;=`@|R$zW246@LcuFVi?|(OPux6ql*4 zC>bH?x|EO?Y{StG&!U{dq~KeerxZsA=gnIJUm%`Wig}8qcPfD1;K&ooVwwAQn)P&} zyR|Td2$FmGh_-bn^w?*wa@!>II3oMjoC9Oycw&Z+;ILs_+N#@52HivciJK?h%VY(7Re{nT$O5G7Fz z=+101FT6;jQ^UDBFf($dl|Hy8kR>vzA4UWM`=Rb?6N5sIBd-4+jF#M;rcAi|Ip=_+r{&<#TH)}%2&ZouIzjgz z3EwCFyux|QDI%2FbEuVf33GE8f#I z?b5>_%?B2!1(zq#C_a0))_$e^_ob87RKuL&QzBEiKodP(zV@!og2R)gI?a^!B7AN* zX!#%9EuM?3&DH44UycmaR&AQj(r4kq@pDE`q3G9-YI_tsb0-UHM_syE7SdV6H3l^! zq_bGi-1od>g#GFEX*zcM?*4=u?!=qDqrJkD;vobOk}kaLT0`_j`83BC93snMN3j`S zqs*sO-`K1`(5m<9ScEX^ogF5tBR1voDY_ApTFJiGnRDB|!CDT66pE-vMW-RDN?X%& zj4m_KQBmC#a_J2cnrgDEwtbN5{WQ^uksrZ=9TqM~31`I32 zbFw#u=93w=1r&%uyKWg6Sr_g`;?}exY|;r#VQMqFD5}rc-mbZAIS4fT=NbI@zvW}d zRq7)n6~@g-E4^;09vyHxo&U)+UVGK0v_t~1BKr{q9i6B0w|Q9VIOeh|F}7>yeEmLK z+o!!9ae@~%6b8ML#G`m^d|qNI%-fSIs(w;ihI{_~9yjX7*yxnx{}@Yt;&dUIL|Z>} z9zNJ>J+6jWD%26CG}`_^7}PF$mDwmt=a=%K9X;tL)dF$Kyf?M8$6-Ia(6H~WwDt#^B=Z3t|{Y;F8)m-!UU#jh^ic$iGS?bv=2O7fT zzL`9XZO(%Cd2PDIvB?hQv)IoU^=BICQ=bVI)cOBl#?Q=1|o#dRaxDD4Evv z!$)$hE3pRY_GKyWLN^A#z}KM1elk+LVB+|t+T5j#4636wc=94zqo{m5m+5(+=xQDU zE+r@fq6G?4}Ug?5_b{T=FiBVgBsPL$a*ArR%P3HRNVD^I_q_)5`Q$mAqc4*&Zp~ zE|`q5YELw*DY>E~;g}_M4~%&rl_%Td-#=wk(tvY{{NdL~qu_K~^@^ksncKg4lV_o< zdAJ2DG-2eOECX@ED$y#hra;J^?yFH4Ls#)pEO{#5!e=9=Ke+=u4Se)`R!# zdJ?kxMcrC5{dfTBX8qW3dJy>^G=qQA@}Pyb)29`3_di-@(ltdobGQ!yZA8cCUW!0- zrGBx{qGV?We?#pU5ru*C-3doH(lq)?ketHA#5hk6%fPy&aU;(BM$^S%J-m~RO1xZK zo=%53!7YEU$oCIxzH_4GA1sgyyFu&$OH}FmP%Ns(PP;KTrDg|U(yEqSOhX#{3KPZR zTmo$vI@+{HEX0aUNOp{XkS{L82$DyAt?O-%^THz=Hsp(2IDFH&7AwxI6pKavI$z|e{E$L45MXl zH}CI;&(n98kEg$gFMoZ&+BAo!t*#TJ?wGlR)CvK%RW8JGWOS777uOb5p;TgZwf!)EWeGJ$xN=*AJr&QT-T66c zo{Xr>fMHQTWY^K47B+#FC){-wqD#tAKT>X{LOI#FWn4hCCURSggL!J5N!gHGK*r2dfQ{iEj8kzD^M-?mE(88JVW`f z(?LQ@+dtETTBpDN@y$O}{9x{@u?sE_4Bppl_pn7-=u~lvb>2KTQ(J&Xkh3{|qT%}~ zv#7dA?}}dr08L#mOOaDZ#fG`zo!hPK+V7DO49QGN=g;03e=63%?@07lMDg9XkT?w!Ze7Auq>}kehK7gNi#W6|z0DYupJcs@}ImyhJRz9X<)g1gOYy@8 z)WseG4xTpth1~q>aex8gm1XC&At15+B*4jfZI6<)A8r$V$V-?l$heZfu_EG_O!|#d zbYmNmu&eDaTD*A_)X^Y&*n6q#jf$T1My~o??vA^9p?B07Or}uAEm^#Ol=xA(TS~3e zFJ3{Z0_OdJc2bTIBLLN6zwgN_W4pA@(rEGxOcYtNg7EH1-{OL z%>T2;W{PBbn6@1;K#>Oohomr=v@N6Ep5( zRB@3QP$wwwK2d>Ikk8!*Im$G*-39sQUD>1X6z7H8q9RAXQ}tT`Z?QmgyKSv|IuMjI zDC{2aI22pIP)#Bu*if?`;mp9_I_=TGY9>nuReZZf2z|$8q%`O{_Aqg2EvLtZzCb zryDyf_F!-{9&x0eTSio~kIqICaJ{6R#qEUbOb^bqISjFe)5RzM==9cwyAT5+z$`oJ zm{SBy4!6?6aynixPm;?Xi|kig@yO|*B2XB!X*921OGe*4W99JkmP{6J!FNkk!Zv7V%}7yspV zj3vCOsSsc42BA<4$@{T@pacozHK&E#H0<6hsBj3xcMY+o> zZoX$(Ww?%bYs!;6ha>hM=8hZN`-kfSiO+N(}|YPK3O=FH`r!7DIP$anZC0s5rbi47VT`H_*j-rxp zFGm+|KBGq^mz{^R5XtZM?X?)hQkK~4?fU?QZ$rPIIt z_$)DEx~jbS>R5s9WhUWgk5^x#^O0PJ+veYn^AlpWCF;&9m=Y!+m_3?Lx-uy3J!rpI z6pke18zUXDM$?m@Oq@1g`5lr=F$}c$m5GEp4c?CHaYdv|wo6KWd8??2{AGb8gOrV_ zFRKpuafqIwn8O*}c9D3#qU^r)7#`8AD9u;~Th?QF&vFT@d?z&LsDb$qk>DqS%pt4{_!zVD{`u?MYuo{kW7|s*C7*5)39K515F+8*8oLc=YU)0A8U@~N)gnEp zc$5GyLQ^W8XTBvDJ$J;pTej6R2{H4VyPR@c-(XM3w-`$rtqNT;^6f$_amWEU@Y?Cj zSN~*Exm!AbD_RX5hoJxV&|bkmn8^}pVT&8|@ei~ec9L-UFKAk}9fS;X%*F}yBknG` z?aJx-q)H0bB25#XvShR7)pM^Y#tnssz@T`2*>jU4qNpN{=Y0u07O(8CIipPSrcQR& zTDOyU)uwZ}kwh9#E4kn?!_65e>Yv_AHgJ6f)-`{CTB0n|V--S*Y8G|1_{F6lZ=A@- zeHC8khQ4Gq@}#M03McZ8x3x^&JUd&uOE-~=NQZA18^XXbr_>nn?_g@^{xn!EnZ)sx-^u_a-}M3-!zBXtPqlb31P!`o+$Am zBY4Jam2V!IEs_uTDp_y8fhl`!iT~MT#smNwsulr+2a1AX*xxu*w3iyuQk$u4=mxc8c@bx{T)AS5S$WosG}iaZkMI$d^QogAK7jHp#i5D z+MVAz-v6>@tDn6M@mc1m%lPF+wn&frW$T$FRg6u*nV0fLmDA#Dwuy1t!2IW1_oO-Rlkzx&o^*#N zqc%@FJXw=BZrs5wL>}P;kXM3?emeCnVFb3jJm%+Rr0JMy#cI zy0v}Rs3$HFi9+!d3!}Lolb#C6bNmaVH`PIyN2%+L`{^wypt<%oez08D3dDQiVaxU3 zgCa{)Y#g|*HPSy%A^zi>>RQv$k-dE}rvXZN-qu#H4e)Fri`DQ0uXxW)fG{*s(YMi! z;=qrU-@9z`YaSacC=3o6*K@C&*LmnD-_V?-jdw=8ZSbo%fD_YzIaqB7u(nWy8Q zO1#_Gqftj**T|;Tg;(?X?bHZ+14cbB1`TF4r>83DGrxPC;;2z&*8-HieQbQxdJ1t=fcu^x%B- zt2>o}T*$@Lgxphn^-Xtx7IRFAZF)~euC<2Z;I?zwG;Kmhh5vhD{7w1`m0gk>t!p=b zx&)w=ALaRcGRbBOke6iQ{Nd45UWVMUO;5fx$)@SdU4$+`KRKCa(CnaT7xP+d)2DJ=qwXtD+pN7 zEF%dtJ5$zeDUZkK2s}%@5u4xL(Q%}6T`y5djqaFMYMh+|6xLhl(c@K(PpV_AyRV(J zb&7XcoX(TzgkuoI{Fe85o}2j_s6@7ksIOT(Pw!X7~d++HYhpk)?{9owQ);szGYT@3z=b5nFd=Sh+>prLSq|+S; zNXt7V;gQyISC{f_XQ7b5dA1t1lG&KH|xj9pLfb?HdtlGx>qoZhS>2}YiY#Y7k*jZoi z_vK-9E%y$zdntUb)t-3K1aF6)tE&Klc_#~gDy#+XAQQYmI*ZiVBPBgTP{Db+mN#^? zeR3os9bCJFUAlMW#+NdfR6Leg*ql;u{kk*h=F;cx{H||1jI!rZMohb(MkzG18|9(D z@%p=BurLYpZcRtLPA1@}^X)vxl_9UXu3BJQv|_!j&%H1(Dz2dQ0b{yP+C>c5P71Xg znk5G>SI}$L8_AOUe5hiAb8i1<@7NHrd`uc{_qLRtS)GdA#Jype{`mH#4Ck{P{V{+P z+szvdE}DaPODCh&jTd5UUa_vRyB!_NVR$*dR;-h07T=*^ZRl&zf^DkCg8!zhvSKn% zqL&iPC9fdmmVz$qjJsb1Hr5D?cl{}b?53L{L-qzPDUc?-@>?Bt%Z}pRRJixq{k2l=)~F>;c|%?qV+3M% zqZt&Y54>~AHE7u-lcFo@dnt*{La~efTF@Np{`g)stR>Nn>Jf#}4t@gEn`wFu;Xo2+ z-Uir5GOWB(V>k?NSKLhn&SHqhSrwL4;c@Jm!0H3nVX3Yj$J%wdu#2;rutvem_AqU{ zn@Nu%#JEI8NdcirT_GB7Ca_5*FD!o?>Dt3_<87lpEQH@mkl|oLp`|_q>6n>l>S8pe zK9TE~c+hy{q}~wge7J!ySCFnia#3VqUu4uk`u(llC4;2gIo9fWU#$qCQ8WpfDQa(& zX#Lozmh%<0Wt_op`{-nxQJHV`M18?L)kSNBxo>H|Q*WNNwsJ|c{21)BM~7NzC#AAb z?6~k1ezfyoQCv@jX3ipV5DQdg+8?N7u+5hYB095%3t#Xkg1-VR=77!tM@P|}ZT&Uj zU#zN<5X^! z@hbZXjv|k0aeDycSh1O-M7rkU;?;g!i$1Nr%y1a5^4adl)^e_}YZx0zoemE0bn}zA zA=x@bMch7pa`bArLcZ%pV_PGFuu><1D9e2<>%OS&Gee^O&&cTiN7g;QhY`LD9*^xb zww*MMZ8o-T+sVYX?KDmr+iuv{wry;G=j`sad!2Xl2Rt*+i+jHJ=hZ~DMv|Ejnz7R9 z>XH-5E&I=CKoXrwSku;8XWh3?R*t9G{4)HhEEO8ege@~`UB3tHOf51D{=KRI^+HSPEaoI*p+IMC3Ix6 zwxi|m$(VuZ2$_U_);&mQrhDhAsfarN-0&hNxKlNG()-RLNzDxTY;Jq=`Smdw4k|~^ z!GLZ$L1Bzmps>TXvQpPQ31(V>c~C{|W6Eo?!-K>}qqK5@#JJvfof~v_@usJbf$D|> zo^4jYdbF^|Rug(Jr{T*-=H$Pi)3iOz4@SFyc8I;Rk!{R(9)F=PBUAqz+Mxj86u&)=@9k&$Y@(?zR%Sl2@ue-gpmG4*?RgX}msZxwk}xOK&{+vR>$(#3 z0h@sHqM}6EsjV6NylB@AJjT9@K&Zo064eyVqOp0hjQ zHTf(4pn(bNrBb5PPWSCXT24@Jggn+kLKhe&KxYMC$h>-)QdLNlFCt_F^)`AUH+vW1G^EPjod?U8j>twk)@PeXd==8kps&`{KBEptocn4pwC3+`2^Wy(cF_V0&K(Ehui zh%93qJt3sDk#|O)j5NacdQN`_xg2ozJVYzB;dVHlu+ElRt}xs4sJ z`9N%jac+pY!w}}x@Mc)f9JhE_M;QXt`8Cyll3^l2HTL?D)Dh)}ynHIU5H%+IVFuca z9D%?Ev}|FbfquVam%l6W{Ed1=@bozK>p#+IQIz|XG_A7~uEW;4?cre4Y1+t;twkRSUl`B}fp*{&FNTFqC2rvsH1WP_WEp_2g?Rjh;S z?qA4eH@eKq|Z=v^jju{!Odf`YKzG1}+ zuye@Ra9ns9gg$m&jvr^&4QqgjB5p}R$u75W9Qx#4qg{#iO7tJ)%}F{fU)L{$qA_j6 z%t2zQIS|*PA$ZPp2g}JbC>efZ4OtUs5?1}+IVV2eN|7qVX{=6+v`TNGxBUVY2xvE$ zS(F`Wc?NBcJqZ~X6m2t#+=_IEND#b_(Mx<8MN^yIWS}Nnt9B))CJcb2hxYJrY?Wp` z(kq|lc%6Z-iS9df;wQtIir%G%PB+5<9bSv-QHJ|P>I(VCvht3xlSdT86tWJ2Dp(>` z#@6odH&f%iraP_sk`Nd4hprx~0%Ae6$9_!zu zUxgzp7s;m0l15pf=sndWAg^&R(6TH)Wl3 z(%rMRxO{DS_i@b(4$Uo9(N8;SPt=)U`qkJ2uE+iRKAEZoZSg0Tle zmrgt12U8$fBPab&u-Dy0M(9;PYtu27L(ie14JUKdk-mSQP#EN)AtTKMnWAwE?@f^< zgyh@Ak6EHLz@GIMOK-_>k2#gFx1jH$7^Tc8`XsaEp27Zvmum)9`oPJ&nZKfV8KKXc z^%H%9+wAR-1d=yzs8ou%B+w>E>DXVeoV&3TmEt@~NS8kDFa5tgLS;%{Ky>^O5*}e3fTzTdxh@cwvW8!w zy{oezp3H5YuebD)vek3q8nnSGv}8_pyz<9w@;;O5&T_gLdCeZe1&}-A=0~=z_eS4W zq;^mR5<;F{W9U=nAr~zT*At;F+wn>#&v>UxADs_nCUgq2XJM7ZsGmC@2pCcfhZ{lx zYgaxXz;%jr;6qXcAA`4c7@@|>H|QGW!zZ-H9+)4hX;rC{Q^^%-;pysG#V05q4`U-# zyTf*ED?!J)Uou0Hkw{hsO7bKNXT23ur)G2h?)2OVys0ynr+x6R`pgV(IvoHCVD8Lt{Y%T+-AhabRamQ%f-LzIIEoGvTp-&dNJ zs1Sl9sDPo`ul%ltD5G6r;VngkJKahYC!!%FKWfO-t+k<{qTU79r#f*i@ALD3i*w*? z_xSZ$<4yZ2@18h6U%koI_3^$L>spYDbe`8|Ipr*u&e;A@UcvHnm2J%1^Ikf3LDb&INM z{q{qI^anvGZa1!b0+IJEn9v#Ie3LN82H`N7#sevDz2~dUX{nczcG85TO2jIl9NZ2! zXg)?QU(5Zn-5Kn2yLWEpK(U}#(8r<`fFJ;a@;5Q@;)y1(G(G%>dxbl%JEoPv{+TO= zQ|go%*}MqE5`K?I&L<_b`G?|2YcR^6fFz$2I3ne93c^P(AEQyDWw+~vgl%# ziES0eMgKA9kDbV@Gzx110hJqp$HiK6cF8j8&;xhf^KN?wRD)hyDG+WeDo#buP#n^J6WY)ha{9U9a~;b8q+7pQjrcfFn?WYAL& zAHnEOu$LfvpH7x(%kQK@TW+(H=-in#?~^DCSH!_l^{$0 ziFGAFPhz^|5dD`v;a*4C@pfUloqCq($?1p1P1rrOfDEA5t=@0wG&aP8@~=M zUQ|Upd^e3bD2r|m?|V`!v}7J`*-XXf5#mo8u>iheJN`tFxH>2g#pcl#4zs1bOPYsl zq%wY{&&Nv>L$crmFgDyc11G=e)R6nbS%N(KRo`Hl^7wKOy%1#|;`CC+7X;q9k<)ftO({s2#sbcYc=2r;J(W&(<5yyYf%U-2S@30Oz#2s;dbq zG4Fh*deU#(97N3-*|3-yd@SNh8>>fOT2GU%Lp&^L<8_qNiwf1UUO+r|iL_*+96k z$U07iM`$}WRyKynLnTvVnV@%DIovO6l%;lkZ_0IvY*n`N-Kkr(#jk3x+gi+FszbTn z?FJa8YBuf?C*$$MoSnfENTSaAO2ZRV$$L+I`X^7&xW3(elZs|MY$yny4FS;TVzV>^ zXr%X5$j9@|3tXu;3(q2?UT&$|lifMl{ZkW3M}l?}4Qe8%axx|G2aL1tisd^AIitJG z*2|D$2DCTB+1u&=rI9@v7z`nm2N=%uk{UsqKDY1lb+9GqQWzmCgGX{5s!AqvZ}$2> za%{WVrE$l;%2DY^*Cckp7y(8n)2x5SPEr=gHXnu12U}tQFqOmv=^HUS?nv1xc5$4Q z#+5dL9tTdrIS+-^M#5xC>#3beDv)8!uuXD1;{f3wI`@TL!70g_4I{J4WqSnWu$F!29z zXI6M_fT(NBW!zfRHofwb=pS}!$97!Ja635MFU`Hx+2U|QA5r{bMOR_vbaK3J97f~i z!ToCOzi^hq^MZxEhu@~qCyGNR*v`A#vsg-qv2~8y*{Hjy;~i3BFe|%$U(~+$ruFw# zeI!q2MWBr&*;K7a1gO?+B464N|3}%Lr_LG-d;Gf91#RHZczAF`XIUM9lXf-COWnk- zXbh*{aGhgog1Wy6wb$VyRN@?Ef3D{Fp;nD3P-p+yUxa8*V#Py9HhENtY61VSX~mq1 zM3{0M*2f^un>DhIX-dY3_w6*zP?LY9wT~!_c%s#;`*yV~7ZBd#ZP0zs7Bo0w9)^ET z2-U9;;FUCrdy+)^G~h1Zx(jYCjhqoHSeR};QN1TkJy`h@E0l@f^ao-MgEQd?U(H03 zOf_@>wYQu{qSZ%h+# zp1iMGZknUz2&hz<59%TWG`5fB^W;ewSx$`Wv+a!;8g4dGXee!D?YxDsmdY0$S&Pg3 ztV{wNVKWO%HHxiIvU|}Nn;ZX~g-(ki%N-<_KIs#$J-oI%U)?fcoix)@1nrIKPtE32 zX~#X67j*6ExlwG=lcT)mZc(q05uYEV>Dv4pJPC3Tum0Fg8Ep$5n%ODkJFaV48ueuZ%*{jiR!8j z3oB*npF-W)I|>l=CRTAlM7_*KiWM#{7R~P9ZRJGf|E-EBx$-mF*07v?tp~KDCtc<3 zVyiVdr*q4#4Rm!Aat-j4$K+Fm86<&1TG`*CU#8Oz`ArsXXtKVBW01G~ZEeKic#|tV zoLFG?2^M6$LneRweVO`lV&3b6PI`;`3=m&DF!9_3zsJR&lc5Ytbt-O$@`;;K;jE=Uq^uyAE2$scl zS0t^O^nM>5T@B#{eJKha-n$1q(xv~R%g?z@bdI$dXShrlilQHm41sv#&l$8ngTfI`Ho5}7 z3vmOnHgD4cN?d4=xcaHO>K9!N$pw;17i7CG1gv7(5J5;A!yn?ecv=T#p9^*8q9CLL z*}cptYt_EJi_1j}8i7#Lyu{0Ar68UcG1Xv{6K?vf%a0OtFrugvMM9ngEp3Jek3q`; z=Ct{&S_WP4!OlegSko8(Y`=Snz(jaks&Aq`JYjqif%qQ8lxr;c5Ke=SZp(~V&}Rv2 zuxme^I{27ICGdq2VuNzXwl0`?dn+A*HTQ?+H7BFygTZs@h!Tf*fsR`~3lK!IAFu9ML+he@ z+Vt^!um0x|GXCz_Y&JnMDCg67y1IICRY=Uqa0U4Z*6U;w!8p2g^X6)>MDS<_K-tC} zz&Hijj7z_!)%kT5eVzIlNtt@P;{+K$zniHV@7XSgXZ&scMo28*lBY%vv7W}^_<7v$ zKi?R?RlomYO%u55Jc50gC5#rO3Z8#=O6Cau9>szRA(a9(;uX$HCsUB%L_&bm*hanC z6LQQ4641U=%jF{FL(W{#kwC-jC`b~@fzsoH5rfY9@;Q=l!XT(H$axKT{#ep>1CO+3 z`oT~13oi-3oRs$>TPeq!JO@ka96@xq3MApWj+YYwE=Vy-khqod1M3$N0_%w3mLQ0; zMsr7@aD*d?Aax=(@n8_qKwnWP0gI>-c=9p=0LqpS!7vPYv2%WQ67Vld{kKbV{uwG3 z=`xoPNfOf^R$Ew9wlb#q>1NP_`-L=_&$pA;*T(m+0WzUKo;Gr+*@phrcKCNu9&djg zRIfjgFyA~9K;Q{zq#9XmBAa2)@InttHf1n`<2AKq{&eL-XfvgfZA$_q47uwJm-RS!|rqsmF9% zk=cTLqOGGS`#(At5QqMECb&}r4>2ydn~nG<8O%6&Y3`Gr9CMN3Q#Tv`+C+qIhOkp~ z^FJxR_`CxtZ2k6rx%Y@4P8Q**$N6Upz~5esS*%Cxi|1KLP3=N^Dt~J_C!&u1w@yOn zlwW<0~PBkvBHHQQny-<@aUZc`J@?Bv3L#|5SuWV<$$>+qD) z!`>IL8`X-?21HBt`b8;`!wb4)$c&`3J**#NE(GXydO8COG6Yxq{PD)@{NP^4tUJFYRbF#P$p5upkrNGBJZ_!o1p$s+HpS- zYw!h?bfWbU1S6%S&cpixFvzmafX^sb2R@#``;a)f2WWPEr1^JgNP}qG-pC?&3-C-& zT+dVH3dZhkz1jZ$M}9luOK)S?74LReBVz7dwqWhIu^EXz$+p&l%U^A zr^C6@Ia+%yYwgHk)%?fv-rY;%5j&|7GkAC@(?z$g8O0jweQFP>j0;ovD`JOKO;H15o`!ux%gfaPUP zft9ePi4bV4-L8E(KGUNeApX3|&P4mL3R9MsDOY3;i(9IlIRL3rCNsRY_Xtf z?5eIM6aG8BG&Bc&fp@Qa5+DI9hz}VKCJ9?Li@r7%Y1r_;6I9ZSAia2J*R^v@5>Yyi z5~GdfgOooW0MJoxr&$MtcUW!2&;J`4rB3G&km=7LQreZ9pwn|wKEdKgS#gVfryB&s z67ss61?NOW&L9{*lLGn{Jut75H&4G$R^UPG@i`Vz9V-o6Ek58jGW8(@N;b)2#536(bLE^(H_BG z5tL8l1gWnftIoPKyX5Xr{(v9Q{}g}Z&X$&ms@Tu%yJ<=snVv!;g2j$eBPwWJt8;jm z)KnMJfzOJi?cQ6#msza%_m2sEF4_jPSikOG6TEKDIe3zU|EJ0#-vbBy)TpvQSe%3U z*Kq+ipZNg(Nb+4dju0q^~{#bhPKnR|f>?^SyXS zoFCVnit(GqavQ>Ei4G_KVw%*}BT%{1>k40^#aC}4X0(oHyo1L2nP~5H?M_}mAaNu}2xmRA>Uf|lE+riZ5Gp7DC@Z0Cfdt#NWews|-5u!rj)9Zs1AMzY3lE@Fuo9j0(r`*4>D? zuVXh+-mvPVMldjFl@N?zxp(_+VQG>?RIvR9b68`jZKuj~|2I;`K%dZubK9iyIqky_Z_hf&XM9e3Ip*3GV&xJyF{FJcO&N7orOA_Eo zNa6O1l=w1xSNtfHX_?YmEJ83juCFTxQfELBYb)87PJQPuPS~Zz;iZjIYZb~&R+dx> z_ihNwhO&#(^exQI@L)d?_E2op&+UvBPkDbk(ea$acl;X0L0(-+{Qk8E9x5dDmy0YY z$qBpeseUPj7I9uTt5&HLiBf@o%Ar{}XDvCLF#R@aD)!<#N5sDgFQqJR8bzxL@bK$v zMxhDAtLPX6sWEvDXRfwd`wn91d3NkU4EzEaw6*;&!QP-fx*i=WQvB<*6E<|cbJW&Z zyX({*?OoLI$SJ8?gcx#?XjPZyH@jjUeiMBKqdo2catjs`)LQImcYmJ=HTI#QVFObY zJ~Aeq9YkBv-ko#v(0c^0iNtbEfL@MtKCJi{%y{U{}5a8Y=UU5WW z&*t0QEsczbnpr5J4+>w0XX+1`6D`?x(A}h)tEidCZ-4%q0|8qR#XIHjxW&KrdIGD+ z@BObpy}Sl#3=1*`Is7M=Mg$Abr#d}n!Eq?sZvBeVA)Sef7fFgc@+u2O#O3~#0S^Ix zHqH`TXetgDM(7is=2=AxkUUd(OO=rlF^jAs9))!D5w zd&DInZ*d)Pv+CMUNP-tzx@ku0;{|<{8mTX)*h8bPjBOdo)NQtusE6uH56wieLt?Dj zy!#Pr?S85-SdHLsjBE)(KnBIcg5wkOqr%XUg8W9K zu&E=D!AaY{v>(y1dh7O-zJHXdySU$jR5(>y-jn`LjyCA7srSG-+!=* zmf@aC(n&{z!-A1k_~%C^mkkmMJp1{HTewRIiRf#)GX)nE#R;r#GBYLKvY|x8fsi`F z`g!cnh&kC4&)+hna6V@6x!kDpu?&oNy=-(vgt`gYGiQsDd^e zZ(oauV5Eisz~*A8A%X>k+fF>AZjviPJG+`Jj%XAZDyNbxvdNXTKbAj-bduQP{hfi8 z9{0`9=-?av-pep|PDKH^rL!V!H!{~bM&2F2(2n(Du&+}PeZTR_!)DMtRqc;^t7%UH zWmBbaFYmwKjrR?VC2O2*jtZJh?+l7lM?E@xK~Y%K^{ zsWYutr7T+99(#pdr4@@1i%nLD8muC5t5jqi(ezCrtD!6zj5(w+7R`IB)MET)nch=+ zE~#3Sop-k_1r-b*&~0R?S=B$D5W_VXc)aZP6P-@*h-xaWjckf|9onC@32?$9AG8Ap z+ z!}|XW8}1$*X=~WJ`Uc()L%W%}_2pymqY>P1iWu;lP{eP4rmeS(|_ z0rR6b{0@Gpc^$sd#4EXJ%d%mc2V~fRYk*?DO}KRR5LizueVG@1;AV3ECV=Qalmscf zsv`=tmF<;@Wq{7XeZStym>X_+7Ou?`oSk1p6gePFNtH9mrFo_vfmdwXxH;Etpwi4q z!&TE9Ygcgak2ws`YLHK@(_PB{{I~4q@Fz&e9M1fh!w!5m0=?UG7EKhK5RerZ3tD|6 z$eMX7@_}w>d#h$no5)iPzIdU#swyq@RE`O%r#7YRNxRrJsY@iP)FXQs(VBip7D)sP z)3QN{X^nNObqu|WQ=|B}M+}A`S9OXayBnVMGRk9;W$8Db@#DrQdV8eK!@f7eG_dBP zRi1wXqrC9xHD2!`Em||`5O~*_-UI8^`YH5#QC#6?)lt!qavr>|^+UFaf4^#ZrH`{9 z(f&l{{@ELr@)Xu0jnsafw5+y$rtZ(>Ol&;=-1qadRafSpAddByUatKO)0xUlmwZ>e zZwr|mXBaeT`q8Gvhfy;PyZkAb<+M*NDjS>lX36rNpK47-PrKR-J3u7(-sXiDky_y# zQqMwv+}xjjCQtGzCswqEAD@D^FnNLJ+D?&WQ8Xq+ExOPP`cy~Rs#XV7+sYn6Uz@~1 zdiUo;pz_RKYb{vc)D6dT1^C9Y}(u6M3qtbbXV?pbl0_?9jW zY~~y$x)RBIU~D*!#sXdNPFr_6^PbVF6mR3VN$b*mOip+wm;^>tv|KDrNt%OpB>$#5 z7*1{1UF^!84J95N4!dI*DvNtfiwucYC}dqi(X4L)2`Hj(E|52jG=UD>sJ0Y{T^9y~l@Cj_q5@gygBAQNQ&YN7hG2c#}vgifK~+g*SyY zNlBq54SQ_P>pCo8?9@4wUKe>$TUlvFL8F|38eicaBud!JuyOqZ&=4HByyH! zR-UYFnbdO0r1f*D#CD{;9~Z4Tox>&C8B<=|aZOSe8A=;!;=lFQDVWu_=nug{GLUYh z@KH_|B^y(x*<7fY>tWO#g-KY->@-|>^)taIE3KL%B`rw-u~u+GE%d-Bsby!GIhMA! zgCBC?0?y)azDDX{hi0XPuB)*%F&1QJ6!bfH%jx5f=Lj`!%; zo=;~|J(+$;smVsSbH=JfJ3n(5Bv7g{4BJk1$F78sby!(RKuUb7eEI9e`e@>$A-|IICukUf%j^lITp z1KjzT3Mo5lNNkW?W9r>fa1~27&1+P)w7wfdx5P{MDP2D7k789vWZ8kg(A=NfW9DR+ zAU2iGompvsjSPjQrp6zGYg;Jd2^uEodSh@Gc?lzn@h%ExL+goKMg7}We#zd&LGQy zPkdN|oD$2Nanj^*a3yVt*UH-JSq}V-T02)zT;qGCY&490K>=+6$xE|cdadZgc%+=u zarGspSj^1KzV}9+iQfDyyXpf#z$kty!N%IBMG7Byl5V*-?d|KU`4JvQlFO<1?wGT9 zRAnz3RhY*)l>L&Iu$du{#{8Q7v2aR4!Bvy&slT;X1Kt**#Xt^gLC_htosJG|?VOC_L=+9i3i(9dyPwAU z77DLfbsG!1d@|MoPDz?C!AMF<3zmL`84l(RDF{ORM8+KiE(RC$mTQp)`ltzk>fzsK zv22)cH?YNDs=98e;7bG`uL=6-yJNGTKJ&eXAwKoqhJ%3FaB%wZlLA-xxJgeP<_YhH zbT&eDW2sF{RTk4mggDdoWvm-Hjg1+l7+U^#ueni$e1bWu64cTib%Et}SJx6mwW$k5 z=&tYNHz$^v2E0~EMUH3Vvrb3oc@}DLPa&EPHIc>y-2cBr-)s6A+#3Ax%C2NotxaY zs-I%gQfM2qeNn-a14u$gGDC!l^Ki7$Kg4;pPA@1+&_t#p8^1%8< zWR8*nlKA}>d@1h&9mSufRhEDXCz{tcgJmL2$`2a2=d@A#<+qfAtR)s<-msvk6WwnR z-M{ku9teFc^-f@}qhb7P5W|<3M?ff}qdg!+J0VE*Kv01g&hSEbEO4d*idOWP_HVW# zM4ZxkM^5FxUkZPwyPrRnSK8_bioSjYc0IpEfHUzIVR78psT+FZ@>V=`r*GE%ML!9C z&3ZO7Gmk+u)Za4(R!}(;zK2sE8A>0>?-pYs6FZ|4`j=Q<{_F^nw@$ut3cuZvm)e+d z?9?TA>zx32)$LvkDv1$@6XMc@+Al{ZVKn}(Z8q zGqi$7>*J_oES9tND_rrT46+7U;$V6l2ByPSzRK;Mj~1d_kV5)0F0TA*>_`HJjY`Eg| zEf3`c^5-c8PgA^g;2LRBfg-Wt#|mC+-pCe*^rnugZM3C&&*!BU4ArNUt)oLF8u6A< zU6XIa3R5RBak8d=?|mj6yJ|`Gn_d?`4witykdXR(`YmnYNTX`_G$!D*F8BA}7_Jy5 zEBxJ$fY6a*tB-_YRgF~(NMYfsQH)99Ppz_Z5YUAZCK*ImQ*+uiefWRd^CS7M{CeO{ z1i)ZiZokJ7^;Y6LPN%9W(^Yj$;UkFNwtjeEf>|9&62kwUxG(+98waIP9Ovv9FURMv`4Y}+`0>X5BXud$arU3v##a#SJi;Wu&yEH0)5Qk8-4ByBZb;K+B^22QCN9s!f5fe z`bOOLkq$y$B_AUiD90`>DkClP2md$l)`JmbyEXwml>fCkFgk*~2On9-5Y&FWfMv~kqQnkH>VguTt(e0WkT?=JOEM(UgSqaLzZG^s7P#uf{v6rskC z%hvrV9X*`;nkc91kO%6TD$q7iYY9eM$K$SXQ%dNG*q3z&sYk2os=INAp?oC(iduy_ zI9I%TBrfwQ#qlW@mE6!L2-`EnT)TPpMCNnQEQ_K&c+IfMC%eG##1OC#DGPk4 zPLi_+xAR5l$+OJT)M= zWX6kEm_$;uqDE&}e`}gbJK&PXBCr}=N~!q8TB3c_sPNN8!(M3QrSxq)LzDJpWLRG~ zkGKA{%0Kci&0Nb_1m*b8A8%)O19VtS(no(}h4jjthL%h!@b{5z<;rn^Mpu2b3=5zl z0{nz)DA`NEF{ipdvA&uAd}EZ02~;ervgQ0lRSD<)LRcVlYhA~I8Wkse1lZKzsnrn$ zO36W9vw1^;W7=lJ)95yBV&jryt;NH3$Cuq<|5%=(%l>ZK34 zhWVy7aqqK-zD~tIufx+u%*dd-7zi43;kd?os($uNiPpR&rIoj(ANBV~gW*i7>T56@hAh2`6yKg@AMCqDr%@o3(56&KAt&&nb@ zUADhFaM)CSuL){8u6e3#IC>z1*ZaHVn&f&!A0vmU@8{J!t_?ewK_FQOgL!yxZqw{z zUDVqOdmXURXybd+Smvl7k5j8V8`yM>LG&;;kP4_7aIIEE7vz2@(}S;uf4C~@_X*{KJYznG{8sBH2M@2xJT&}SvM74;P6MDK$SWO70a}m7UB~!b)^YS z14GHnK2iCfW_)0i_IL!ubrcF}mttK})W#_lt??UG(LJT26MpiWzMOp5* zG3cpL;`^9(vbM}I0L=H6@7zaiiM3QuLwPe4r}gGbMdp%IXU+9?*5_nPhqJ9>}u-~Ir z=Y}5z#svZBnafeZ<`G2@x?mI~sQ6VJxQDcYc`;O|(8xmnWX}HUa8hX*pSAC6&EvoA zx&7m>-A`M|#1Z88+@iAMLO<)Eb*`J;rO-^%?(Za^<&pQTFj|i`&bdBT-pNe6;i?l| z71zDfVwA5M_96zHG@Qr8G#<(#+L$db^JHpzCd=> z)#Ltu`^AaWGM(f+N|;)>t$5!PB^)e|)ta_`s_~B8(R7NSj~|z!V;L}##0GDT-H^k~N< zy_x}d3n@FA!-1A(?2;8#awN=~Qg&K~1uq)? zM00(&jC1rZaSl6RE+b1ePq`Qf`rt)!)Rjz2E$;ldF~01axH$-?I%h>s@Ihu|Kj6#Y z)A3*N7_+)ey`3UXN!*%O4=BYiT7SB?;GY9v$J{obbk*m+OEacf&)XeIV#W66u~lP^ zy3xq~C4wzNy&#&W)gMcIlXe>kupfvEQ@&|ZLbq#93JutV{&?EOT{TAy0;4n%dRO19 zTxE60=FrWn_f33Pt$1;!P^e;SPWPL?zeeG`Ji8bqp_2t@Kla0pBu!%T40~q#Wv_vZ z&_Fo9Kbb|FhKrw?V|N2Y+P-uLnlK+};|vS$W;SrLum!v*_0&ZizEP<;Y9OjbT6Pcd zUmHU8=s4s-q^eylkMngDWwDbW6<4R&D(u_S(@X~o1nCY-v6#cxujX)XInH9_hi+b< z#R))VJ+Ls^gUADQt~^Htaxb7V7YV%0H!ce(&UL&&b%-p8wWKuO#wJ3kvVv3`^Zv!2 z|L+hLG@Rf+A*w$J@-$Zo3gbm#p<4a^=BA9CZ40hY`I4wj_70K+C~67QIb~CgsCnz z70X;(FDEkX{oBeE+omDx; zXw-?HRx%>ns+|#$*6ZxB@SKGSJyAodbS$sus#)}zipm;w-iM99^>8~4uWj8pPFKj2 zjELVANT!_Ogkg_!X|@8|R(aP9z7t&-$*77J_{ws{uh*7qFP&*8Sy>cZ{2Z%t$5qX_ls2Cis)tvw5XXj8YBZU`9is~bgoXXcxk@FB%oX` z=q2_!mvoP(i_|7{bu_#cC5PuZMo7ti3EsAH^KZM@PZ3y&>9+t{nO#w*%r;xKb(U>; zUu{H{Sg{cXxV$u@nLys*ve6-q*R|)4ZTkb|m&Y+r6TSdwstDM6Qf^}(J@jYf(>{i~muQRjUOwT&;e6Ll;ur86Xm`hM~3*HxvK}Da} z&x(ZF%#vZh4}t4Um^Ee&3=A^s8A$+JIH&v8m{;1v^y~rDo1(9#?+CNUx~So zH|eMX*3aU1JU>3${!acd#8@q2Dj!Ryq9Dh)eG%v;M0^1wU6e(sn{`Kx+RhX%nKWo# zG_BmMAKpJh?`cQ*q8SthE2J(b3a3Caqj*Ar|3F5Ce*+whys5{wNEYRp_AY{$P^As8mW4kV>|#`4>G*crFg2{XNKJ=5=;SPA_tz731}SPEUz;uLww)9M$6JS16RD{_ zonB({D~GHcU@Y2{X(~sk7=qM&@0gYWZ+z_ znrduSy8xA0%4rrGp`@*w$_P2t>*N}Icl2SuSL$5I_;f_*)#Sdm`yrbJRSVw7!KP2N zalBTy$gMqS3eY%s^q9NcU8HDd79)#!jka%t3loM1odR-K>-egaIJCAU6C9J5kIf6t zD^XTKBWe*mXsStaYOxjXbgPM^;de~Bhd7F@{s6XRW?14^HDr16y52&09Gm?GHGVvK z>qWoU`3SC9jjJmgwhfBl2E-!62eW6zY4I7htQwI%$S zPW*OP`IZxfZF#N?v)Jjd|p}Th|?N!ZSV@qVDOnyi0Z=RK4UjT_w87Ku?dJ zvIzv=QK?2kZ)o?3_wK6iE-MRoi(dH(q75ubb%8a>Y0up^p)7;0%<(Q28>NO>OCb{Z zD&;+aPceayeX>%Furc`BHXW2FzUQ%KxVx?dvl$a~|$1D+!A+6asDy!qJuO^NVTY3*IL6)GI$}X#xt2!ppN? zFJdweoT-I1;vtkJD3x%j>`$RT_ej~qPhtP?gEFT6bP>Jp5}fR;oddig zrx_%d5IMF{*il{>v#R^Q}}nzm2&Vl2N~F4E&Q zcaEK$dG}i?JX;GKNc!V0%I!*F$!Jz3`-IabuhDOzfgviq%~GCHZR3X>WY=`VuJ|j^ zX!5Qr_Y)25?=6Dwder?Br+iwN3K;urJ6Djsf`Tyl0P^rmwm{kS!6qO#0($bX&L0V&RXt=pMCnj*^)yb)ssdnc}|VFQ4OOe zv5)y28^g+JlBuVzL0B|M*4>AjdL+%wQ?Murn>jUN8CCo`E#bH$n$q~ zb;#}TU&k1}q91I-7J)b{N>7YBe4pwP8BS3xx6+z7KKk8wY^}dt$zEaB%+WI{Y@W}s z7m!t(31t~s*4deBx$TpEWexo-r>O~y@yo!C)WE|v#X8c(d^XDaIsry{w&uM%(y1z# zsam~7U~r%>5K|)#?F&?ES)O?4QSj%9ISF-(F;YGXgtsvXD#-ZMwTnO~G<2U$SW8PD z-Uk8hhVzilXZjztT&Q^h_dE`|D!pZCqZ0e5B*)2g2D=qfFqA(kPcW-K3t*X3jJhII zkZsoKtGD`CTyNBA&%oa?6<2gr*$l%2n}w7C2@lY)S;@R=O{#5h9FOH6m{Fw6XQ^2Oasl5f>#6qr`uP+J_{B<8~;+La|v z_r+wks7i)gh^XrlV(h8FE;C1)J3pm^FOF0#!7rkJVwWp7AHZp6XSz4HT!feWSAtfU zj=WJ387=O}T2H>EIV--jElI!qv-t8`)L12%O9WMk4EREf+SJ}nzbR`ZqJ}S(V=0mJ7W}JZEhJ|pimT!<_;`HT0`Cx9f$cSEBz%L^!cP;D|v+00niH((HW7Hdd zedlE3LXSiKtAf9pC^1G~x2Kx|-aA)UIpH7i58C=RTW92yVAmi&2v_0dh91@IU6|@$ zj|iYA+=1`^RifTC-mx09e*Py!y|nAk;cErpFU9|bsOKX67v=;1K~EC%0 z{N8Ru*V!=DzM}UU5*1ZW(f>#h(NHzGz@$TaxV(k^3M6A~tNsHHJx!?#SHERrJk4?F z-9NDAuZ>DWsp?|NoSr3GB5X^9 zL1hSSt;6ELy`gF3e{pq>-I;aKf`(&MY}=^VwryJ#+sPB#NhPV+wr$(CZL{;9(_gyB zSReL3*mI4s?s*xta3?K2K8=T*+%Y+Uea|{w8#L8!S0zv)zEnAr4XQyo#Yl)lKu9i& zkKxSrEWw`bzeedHV`rx;$j?51%n{TiNK}7DOxbsS4zw_0&je(xPL2Aw76m#;}GW56z)d+|X-u<+VAr;?m~8h}NY zT`Wjcd$goJovaHE)BF1n%z4KC7D~s>%6yx`1|)gPMY(@?AM-!=8waj=tWXcbwc@w{F^~hJx~@@ z2Q(L-xZ9A=>I_VRW~Z7ZSUeV06*4!Y4(k5NB5EO#{L0(LbhY|`irJ>|1}JVfL1ipF1K<51;TQ@Wpubiy7aI{ z(@25WiVZd7SbM9}7RBu79E2m93L>MH-o+`(=ZRJyMEHm+w#|phhIHY*{V&05xP@lH z=8fxYVfzzN_oF*FKpIQOiM)+8)6eboQbzC*U9zK~fV1{$FOnV3;}}p9yBaNYPJ-t@ zD?Xy(lv7gFun}iR#WN@pRVm*2&WOD@Ld>ueA~b&BhTvrq$Ub(CeQ|{pWqklo8_-nAX;$Cu!xDoSoqj2&c@$2+P8WJ7VRSw| zPDCGAsfUos%(bASyVxq;xWA)ngC|4&1Am7C^~~4eAZU~_no^3`X!DdTTY8oKy8{~K z3z{z2SIMLS5WEiV;tDLE(}Tz0!-V2JgS8Bs4jm1_6i;eHG8Y%%3Js!**>;% z$I1ZffH-IG<5s35hmY+N**k3_l7o4QxgaKlg(u#brU(66djF|WYnN>9r9}08w7ClY zn3tp!Ugv6^`S){cPy&Ym6K{Va>FvyPspDfkcdk7HP~<4jvA)3l0q5HotXpFsoIH=SJXTwI4L<=~Uc<7ih2L=N<)#XY_zfqP1(y~f& z#-ku$In?O#>QKhBPw_LJy*}kC*(qJec@PYE=wJZjN-YgC-zQ;=ztg0wR?J)HEG(6( zkVms!kOxbd0T!VXs*+0P#5}|1%n_=pshw2rs}9eN1b>8UU*wWS13xRa1_+*FT5#90zxHh7WCW~FcmwSH^3c5pSM9UVD99%EirIPSD9J^70^`Vk_3le!C)q7k34 z!g;4cF1d@cbfT8X1C(V(mF=qNBGWEFZt*ziy=H{^m{00{Sw&q!L{1JlzODgh67@9{ zM!DCHJhLJ4o%o_vC5r39t#4{PT|2u=KX^#TLeby4Pfu_1(WY7a=QRq)=NQ`>!D6juw zbZM``0i+nbVh51BZu}%LK|*8=qZqJzf8QebHdFa}n4S)0Cvw1xRT zWY)(#u*9~@3C97b*ElaSb{Q+47I$p9a*9~+%fKAKjHWhQY-VId)KWdL?Tc1emC%Sg zSY=I-c|5qEpByS)*N(IJOJD-H<_T<{iP~=NN()b^8IiAxapbQ%Zkv=k$Mf538^kJx zFP{oYnrj-DpCi{J>JjRQ6%LwK2&Xbyg~TAF-bTxzfz#8|EkTMLxgLr_9e+nW4mQhd zTS(!{8b>?FF#M`Q>hc|KxHfuG30jUevAOoba;B-`%ouYAL&?{Uisl833pox=Q?uJ9 z&Wig??i5jWFS014s$u;0s{7arSV7dHRG^6N*$e-Z!|^BYEZY4L%?#A2&d9r7gN9h; zaFtfdiBRU-QuOy#S+jHz)SRJAtb1=*g)qcpnrfk%@;3?u|I5^ZnDJ6nn0B0WIPF;|E3n}lfpU&YGsiH>)nx44yUfcO+f z4ik57!Nh=DK9k<0E0)-!Zr(vJbzlrYE$re|M8}y8zpuF&dnV%LK@PN=4*zF=GQr;| zop$E2`G_g#ONt9D()Z7oR+YzuGy|1(&3Bt=hab7{)u+PZn@t4t;oXhsHdeher-yIV zA^xEK`%DVtz1jdEA~655EK3Q+;}F0q`3#8yW+XKgw3YP7O0#Z^DX~k15I^`VhW{;{ zmss(ymS-CKT@#ZJhvVGu{@zjN4Gy(@LPI*4_OT4NzKriU13CXKM@1zmO~HHZM)YLk zQlaVe2T>Q?IxKUOX;+^7%u%OUYj7CQ1Ypht$w{((i}5Y3mB z=hiyawq;A3p3m!fW{LUVEi27!-nQ{)$rg>;nUoT>S2=glBnT1!gpoQEEPSf$o*I@i zQ9NUD#xWTI6PEIOxNFm(4~orys@%QrUdT806u44{vD_8b2FD9Ux|>vOz(cB>|L8<` z?f)p_^TYjguUVU^<(*UIuZ1D)Vx57c-5ZwV{l#E#vnlj?z9C6M`_-=%LZo z+eNxHx@HE7!%}5hHGKEKxYot%&{Y4mM~6oTk@aZ;4vTjYByEaDJax*q9}LX2r}dFN zuKuuu>Tq;-;hr|~ow4GmNwCzMm2u&(X>Bns`&rT*x=g3~DkB>&1A86vKl$Hq$tO1s z@(4tAlz4=h_+>m6I3BD{x^P7=V<>YRFb~wDnVBj~%CVzeVoD5<^JQO=VfGgKbg9Yq z(tg|mLY#*tk9ntFf+1cSc!c@#c^bPCD5S$0yWtfre0W{^v%2rbgCPZ#wJV_CNb(?M zv5C*#n!A(V`Q;did;g13AyrUio9TG`Go0XsQAr=;oMIA~6PRHWNMR%}!39MG0&*mf z6~I6x6qukQM1V&z<0(NR0>XB-K}$}~-L?SFRbE}!8Q*kI6=zpc?XK$Tm&H$4XS0nm zAw5KhQ0SOlK7j&Pg07NCch3vJ5Xehf$P#3}2ajB_(PO*>}6rUuJjXMq3{vE%WHhqtAJKUb+-PQn{ z!-bbapl)-~3UXJeciX0n3V{L{#=D5@Ee0#k4QNo@0f=IKohZOh&~i;qQ31Z)5TL*Z z<}b6r25*V5P%HdTQtiAC`B&30b^5Ds0iidanP5%rAm6NXrO)NGU2)%h$PZ4gQ1*TT zd_sV&bziJ!TUkZ>W=zswiGDB4^fdsT`kd^axYFbr-;Y->?59S>odL%C|IfGQn=NyH z4`K8zc-(c!r^kQ+M`-Qih+F>`Pn2X>?Q#3)f1hQ%+kL-YZCA3@fz$?4OSgr|F{dGf z@i8HKXPS(gxnAKR{j}BcP(I9Yubm)xX72_}T$M;Vhta5B)r=fc4!gX+MfMVyB7i}!WTl4RCF75zR z78M!iuJxO3o9k;nAiIKTl_LnIGs+UveC(Tg_v$0>A$nbLgP*qzOh5x$Y>!8G-5j5qu!>G|++J zDGOZ2wCvH^+Ij>*^aBjX(rr)w^75|fA-G`Q+Gmh~GnN1vKnMtM7v2!CrTqB~gCAVL zIRwA>nU=YY0U;_fNL*(8b<;CG7qIAYMyrX!uxRJ@JCygEU~bvy>lH;(Wotd#&t#8=$*vooQD zx3&8@<#~JT8h97v9Opvf2)2mJ-{bp{xf@)nZoPiWK#CzXMsgPNwf&<7VWOpbGk8PUZ0_duT>BBrc zf^!tbETJR{>P-jJum}$pjRR8pMMV}OLj1e8gc1{NI}!x=8~yd^Zugs*KtOo)*$s8& z+nyx})q73>1QYvLut}8FSXHEM`3cA13s}1|iifbNJv9T^Kc{w=Qh>|ZZ}sI@6FFpR z=&~g1_r*rjrFcjx5*lx-pi$Cby;`?veN0UHn!m$ASO4~ce@8ov>B8(ariq1?3fg0QMM_@z&qFMPVOEsK>^Q=#1L8Uvt%=2qC@D1gi%jph}xb8HP9L86WR>H<6o zN)w8ynYNOBQiO!U(FuHzLM(&Gq$!gvR)S@j2RvIIk>)wiy4GN{{V8~@qN77ViT2@W ztYgX$8qc`X4#z{wi}#(%ZX`mS5PEa01F!KYcvIhFzN1-|+X~L&gpY#3mN)4A zEkmQ(2Ox#XCgVotvJX;!RbO_1drG@u9hEaTOar=GGTF6{3o=mN*OarZptgm~)g#9- z%;$uyn~yHpp7RtE#=o3J)9|drrTn$E7~R=?T?Q|avwXm#0!1Q*!9;2W9$)D~I7UfF zS;@MZM^sla+sX|eTk>R~)MRmC8aVp&2#W`09&m4CN=1S!u>TUEHDja>ip+tCb$UT* z^>Q6S&-J68Y6bxtsMp_oO|akH0>k)EqaQ{%IzrhCQi4OYyuajv$bHQC?Zwhr6P*QG4SGp>k z0fbD6#)m>+-rz0;=8`ShwlbtG>AO!)ixS zt>1qi9k+4EU~^t*52TOyTNnFE{{|i?uiD^0^RyUr7Q^qPfFP3u3NkMrxb<4LH-}{e zu$tuGlpI$do7f!};a?k9A6YI8$T9cJ@$$pSdCBL3MKnbcW4OK_T^EEUgJ*Md783#u4>w!@;=-)#9aP|& z$qUm0ur{GdMz>I-x@=pgdEN`0PYYLm6RX~Ee-VaECkue69liWub`SR%UO?O|CJ_2! zBj6I4GboeiylHoLg5M`nyUy2YgstY!l?w~#V|C>S_(qN0DZauCcgdz>u$M?+NlOyq zN0Y;Re{bU~vY&sjWLR_qP!TXthw1bvlshj}bp0cSJqqw~q>34qrzY4?n}GKbE!58} zjh0SxH0h>eKE|plU6#^4%Q%=u%C=ubq$d96`a^R9YE@UY$EJlQKNkKGjlveji*=+bFJebb~Gt(@NjCYd0nV;27=W9hql+}(=&DcVYYV6 zHa@$8cScNY{-a&W-S_+Jq}%uKz#@(bp_SG_9PaUHk8J~A6y_?Ty;PMK4$*-tj>x@B znUvuRr!i|C^M7C$!=!tE_YmgeVmL;MTGw%YBUqUnic--jibIZ@ce4~3GZ-YxbWiM2 z3wcOHupLCXS8ss=+9Tv0v4$Rk>$i z=HTJlNpi>H47unuq7EA$o%UnkrZ9o5$6Fi<18MyO)wu=Tsre*OTmE)j?Ve5>iS!Lq zLLmZ0DeA+XmK z=Y_F5was2eE^dqsG1JFF4m|EiHGP-&qoTg@c9UmDckNTC4}-57x05FUk|) ze_P^F2LNtx6pmA-Lo_?H?zFR~{0i|fyBGW@Z3-C5R!<6Z_AA{al#`DhlZe7jd}kR1SO^UmDDj25(21bsbda6I9!V<=jEHoDd{nQ_kkek^@D07 z^%2KL$q;1me|!nSXn)zadAZOo@3+5y6Vh1wAnwTt-tL|cEnm6|NuI7?9z~H%~zw8>oK+N8CNTWXlJ@beaG^JVui}^48l%O+ZKf~(tKJs^aFw!MS}}L>~hJH zn%rn?+KCyEA~Hq0pR8%Dl_jF+AOTsDfA4J;n(aVt6$Gii#>8<>hGg3F6_Bk^izi(+ zO<)2R7dTM+K|`i(ZJ1^2M}h`h1A>ZP9%EamK+jHbJ}GF(l0MMP*duH8hPyg~E}b75 zwbQ7q&USXRosqA0F>hBPY`D8h!{Cp`tqvce)s@nXd@|!E2qb04<)Pb%=>YDB=LKx8 zjj5fZBU&DR`6mvKW$+2MMND0Elw1ZyG`NOdN6s(U=QUC0kDCrb@2+X!c_h;xO-nvS z_WA@u`l(Ycm)&0zvRr1F-puaA;o~GAB94$ zP$X#owgjat=;JkV+3XX{?gLD$94T7J!3yir%bGEHc_h=CUPmr|=_=f}X2l0U=1=!HV^i!r(I|ra+Fi*IPVqG+Q)7S_7Z^M7joc+nm3* zeP%a4wdV(z4GRZ_BLRTH_;H2ZxqtcpLrsKF<7iO?Xz8#kKP41+lO6riIP1D9WimNP zipzv=p1Dy>yNLB#R#9D%8{4Ym)3s_dT=1$^vh}(O) zf}WytaX!ZP*4Y{yZ7Gt0zur^suTfa47T-gQWOS_ljDp(R8v0Z1AEc{l$EGpVpWJol zxE(M=qAa7Vi`vn4RLkX#E%?#tWcKE^o^5;`f$)nm9mbqqnj}Vg4SEq>WdUr8vF}f! z&Fv(%_+4x(AOK0ZuioP6hOx4w$K)-;w&^r$^w-iYHy7UE^^I}^{O7XELi^97^KEo` z&VlSv2HcUcdTNt8?XosbPkzmnmh?%cYVLaRMkVD>;eYN2ti$)ucP9hFEmKaYrl~Nn z9c-6QliaJHHyyBo0lb58=YwyYUdOd7kl`35sk}V2SOB#MJ6=!fse|PwVD{tn!j!pP z3a=LZRLhZ?#?zzNWy=K{D@xMI_st}7p_CWv?YxZErdmlS<}|&9Rs9p~3a3f;sc5+m zMhd@J)$D}*6FT~Q6`cqFw7(?)%o(^1wl z4)C<yj9rWC3;ja5;;DRSioQ= zO2u7-eC_HAFfi4hKl#saY*71nYJ&~~CvsLYGE7f)sywEa{7q&yCKkesy{ca8K->%U znHj5goDTgZzeCs>HIqF91ox2eSu=$sO0^y-l9`+KB{^AqOG2CbEG-Xs^;O(ac z{BS@ipWYk)7dnmo4?2a{X9ldf+O{u*$;GQ;>|c_+lLs|6AYgq%c`vnp;VbuGG7J#? zNT*I`q!uzXz`x!%c!>d!N@bX_vGI}BvHa9M!`A~b{h^M}n*-G~PCE|k*ADNXCwh#$ zua7sA>K_%h3Z%u0<+%Kp)nt4yODc002|B@a!5z06oc$k{%IY?yPtW~@<<8Y3 zmf8YBX!s<{D>t0a!y&Z;ni2khrTd%K?XhE{U-cP-&MMf9eQCbjLk59&*IHr1DzCaI zhp;)G`$36OxX#)q5WxN=$a{&Ghq#ha&{fBN?{8e}@6nTg;22IGJq z{iw1hmOzL#TS?LAQRv(fNb%E1YQb+~0?9)i>$7czz7N(Iiy(1HDaWc40kmn!`NMle z3e?|qmOD2eVjT>98r78GpS!NZubBh-<#|Ml+&-?YgO1+S6TtPN2Y&Z1-Ga{efX4)Y zG+|H*&2uY(?-0|$mT0;FhZn)TvfzpAT9z%*7~k>$o9x=k)@5RF{Y)RrJr702)HXmr zCZJ3#=$PC6%?@SZH+Ab+Zd039QUft@&)|dkKX%py*}t84q7wb{kFquB&Vrb~nO(f| zuAi(IQSd|D`v9c3w_2Ie_+VqUqh&dKR=J0ogFwPN<&<5Zc_BQ!Q9pItuV zVncYr4F%x$XN81`Ucaxk_Q7$%c6j&p4DRE53}Njp!vM>c-!l=fIxV84!|$pNNOZj1 zY6FU=aDE8|{S6o0FA}io*vH*X1z%9K-+)Fh+br4SZm~&{BxuN$~?f zcgWDuCxD!uhYQ=$)p(_nO-IKEiZHzh%k|EGiz1t=iw(VYV^E|`VpOrbO+dY2&!C7V zTqo_y#yS3e`U&DO4u`*MkEP&}}QK`@k`IZ0?V`z}UmItVwnr%htk4XJ1`mU9Ui{2jOq6TV*a4RXgf)UT5LXr3*qa_?i-e|X_ z$?+5a6Z&_|o}jo{7=Z^`#7~GY+a4jA-&m|ZacNHp7gi^mq(VA3oV*a@apO~M+hY

f;$FaMl#;*YQ~0ChojN*33aP& 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%0Aqh7SOUQk=W4oN(;Ql$BTY7v@mom4vohAlkYXRj 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�ho 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≤RC9W8_G332{!1 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