diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml index acbd9a3c29a..436c8a57b7e 100644 --- a/.github/ISSUE_TEMPLATE/Issue-report.yml +++ b/.github/ISSUE_TEMPLATE/Issue-report.yml @@ -5,7 +5,7 @@ body: - type: markdown attributes: value: | - * Before reporting a new issue please check and search in [List of existing issues](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue) + * Before reporting a new issue please check and search in [List of existing issues](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue) * Please check [Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/index.html) * Take a look on [Troubleshooting guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html) * If still experiencing the issue, please provide as many details as possible below about your hardware, computer setup and code. @@ -24,7 +24,7 @@ body: description: What development board or other hardware is the chip attached to? placeholder: ex. DevKitC, plain module on breadboard, etc. If your hardware is custom or unusual, please attach a photo. validations: - required: true + required: true - type: textarea id: other-hw attributes: @@ -60,7 +60,7 @@ body: - v2.0.8 - v2.0.7 - v2.0.6 - - v2.0.5 + - v2.0.5 - v2.0.4 - v2.0.3 - v2.0.2 @@ -77,7 +77,7 @@ body: description: What IDE are you using? placeholder: eg. Arduino IDE, VSCode, Sloeber... validations: - required: true + required: true - type: input id: os attributes: @@ -95,13 +95,13 @@ body: validations: required: true - type: dropdown - id: PSRAM + id: PSRAM attributes: label: PSRAM enabled description: Is PSRAM enabled? options: - - 'yes' - - 'no' + - "yes" + - "no" validations: required: true - type: input @@ -116,8 +116,8 @@ body: id: Description attributes: label: Description - description: Please describe your problem here and expected behaviour - placeholder: ex. Can't connect/weird behaviour/wrong function/missing parameter.. + description: Please describe your problem here and expected behavior + placeholder: ex. Can't connect/weird behavior/wrong function/missing parameter.. validations: required: true - type: textarea @@ -128,7 +128,7 @@ body: placeholder: ex. Related part of the code to replicate the issue render: cpp validations: - required: true + required: true - type: textarea id: Debug attributes: @@ -137,11 +137,11 @@ body: placeholder: Enable Core debug level - Debug on tools menu of Arduino IDE, then put the serial output here. render: plain validations: - required: true + required: true - type: textarea id: other-remarks attributes: - label: Other Steps to Reproduce + label: Other Steps to Reproduce description: Is there any other information you can think of which will help us reproduce this problem? Any additional info can be added as well. placeholder: ex. I also tried on other OS, HW...it works correctly on that setup. - type: checkboxes diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 2a9b0ef82e0..03b3a76df1e 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -5,4 +5,4 @@ contact_links: about: Community channel for questions and help - name: ESP32 Forum - Arduino url: https://esp32.com/viewforum.php?f=19 - about: Official Forum for questions \ No newline at end of file + about: Official Forum for questions diff --git a/.github/scripts/check-cmakelists.sh b/.github/scripts/check-cmakelists.sh index 98d9722ad83..7d4f6b4e2d9 100755 --- a/.github/scripts/check-cmakelists.sh +++ b/.github/scripts/check-cmakelists.sh @@ -1,4 +1,5 @@ #!/bin/bash + # # This script is used in the CI workflow. It checks all non-examples source files in libraries/ and cores/ are listed in # CMakeLists.txt for the cmake-based IDF component @@ -12,10 +13,10 @@ set -e git submodule update --init --recursive # find all source files in repo -REPO_SRCS=`find cores/esp32/ libraries/ -name 'examples' -prune -o -name '*.c' -print -o -name '*.cpp' -print | sort` +REPO_SRCS=$(find cores/esp32/ libraries/ -name 'examples' -prune -o -name '*.c' -print -o -name '*.cpp' -print | sort) # find all source files named in CMakeLists.txt COMPONENT_SRCS -CMAKE_SRCS=`cmake --trace-expand -P CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort` +CMAKE_SRCS=$(cmake --trace-expand -P CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort) if ! diff -u0 --label "Repo Files" --label "srcs" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then echo "Source files in repo (-) and source files in CMakeLists.txt (+) don't match" diff --git a/.github/scripts/find_all_boards.sh b/.github/scripts/find_all_boards.sh index b474a49bc2e..67b46661ca5 100755 --- a/.github/scripts/find_all_boards.sh +++ b/.github/scripts/find_all_boards.sh @@ -3,7 +3,9 @@ # Get all boards boards_array=() -for line in `grep '.tarch=' boards.txt`; do +boards_list=$(grep '.tarch=' boards.txt) + +while read -r line; do board_name=$(echo "$line" | cut -d '.' -f1 | cut -d '#' -f1) # skip esp32c2 as we dont build libs for it if [ "$board_name" == "esp32c2" ]; then @@ -12,29 +14,26 @@ for line in `grep '.tarch=' boards.txt`; do fi boards_array+=("espressif:esp32:$board_name") echo "Added 'espressif:esp32:$board_name' to array" -done +done <<< "$boards_list" # Create JSON like string with all boards found and pass it to env variable board_count=${#boards_array[@]} echo "Boards found: $board_count" -echo "BOARD-COUNT=$board_count" >> $GITHUB_ENV +echo "BOARD-COUNT=$board_count" >> "$GITHUB_ENV" -if [ $board_count -gt 0 ] -then +if [ "$board_count" -gt 0 ]; then json_matrix='[' - for board in ${boards_array[@]} - do + for board in "${boards_array[@]}"; do json_matrix+='"'$board'"' - if [ $board_count -gt 1 ] - then + if [ "$board_count" -gt 1 ]; then json_matrix+="," fi - board_count=$(($board_count - 1)) + board_count=$((board_count - 1)) done json_matrix+=']' - echo $json_matrix - echo "FQBNS=${json_matrix}" >> $GITHUB_ENV + echo "$json_matrix" + echo "FQBNS=${json_matrix}" >> "$GITHUB_ENV" else - echo "FQBNS=" >> $GITHUB_ENV + echo "FQBNS=" >> "$GITHUB_ENV" fi diff --git a/.github/scripts/find_new_boards.sh b/.github/scripts/find_new_boards.sh index 706676b4a4c..4482aa2b1da 100755 --- a/.github/scripts/find_new_boards.sh +++ b/.github/scripts/find_new_boards.sh @@ -5,14 +5,13 @@ owner_repository=$1 base_ref=$2 # 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 +curl -L -o boards_base.txt https://raw.githubusercontent.com/"$owner_repository"/"$base_ref"/boards.txt # Compare boards.txt file in the repo with the modified file from PR diff=$(diff -u boards_base.txt boards.txt) # Check if the diff is empty -if [ -z "$diff" ] -then +if [ -z "$diff" ]; then echo "No changes in boards.txt file" echo "FQBNS=" exit 0 @@ -21,7 +20,7 @@ fi # Extract added or modified lines (lines starting with '+' or '-') modified_lines=$(echo "$diff" | grep -E '^[+-][^+-]') -# Print the modified lines for debugging +# Print the modified lines for debugging echo "Modified lines:" echo "$modified_lines" @@ -29,15 +28,12 @@ boards_array=() previous_board="" # Extract board names from the modified lines, and add them to the boards_array -while read -r line -do +while read -r line; do board_name=$(echo "$line" | cut -d '.' -f1 | cut -d '#' -f1) # 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 + board_name=${board_name#[-+]} + if [ "$board_name" != "" ] && [ "$board_name" != "+" ] && [ "$board_name" != "-" ] && [ "$board_name" != "esp32_family" ]; then + if [ "$board_name" != "$previous_board" ]; then boards_array+=("espressif:esp32:$board_name") previous_board="$board_name" echo "Added 'espressif:esp32:$board_name' to array" @@ -48,22 +44,19 @@ done <<< "$modified_lines" # Create JSON like string with all boards found and pass it to env variable board_count=${#boards_array[@]} -if [ $board_count -gt 0 ] -then +if [ "$board_count" -gt 0 ]; then json_matrix='{"fqbn": [' - for board in ${boards_array[@]} - do + for board in "${boards_array[@]}"; do json_matrix+='"'$board'"' - if [ $board_count -gt 1 ] - then + if [ "$board_count" -gt 1 ]; then json_matrix+="," fi - board_count=$(($board_count - 1)) + board_count=$((board_count - 1)) done json_matrix+=']}' - echo $json_matrix - echo "FQBNS=${json_matrix}" >> $GITHUB_ENV + echo "$json_matrix" + echo "FQBNS=${json_matrix}" >> "$GITHUB_ENV" else - echo "FQBNS=" >> $GITHUB_ENV -fi \ No newline at end of file + echo "FQBNS=" >> "$GITHUB_ENV" +fi diff --git a/.github/scripts/install-arduino-cli.sh b/.github/scripts/install-arduino-cli.sh index 533b39c7ddd..bb7f544e752 100755 --- a/.github/scripts/install-arduino-cli.sh +++ b/.github/scripts/install-arduino-cli.sh @@ -1,6 +1,6 @@ #!/bin/bash -OSBITS=`uname -m` +OSBITS=$(uname -m) if [[ "$OSTYPE" == "linux"* ]]; then export OS_IS_LINUX="1" if [[ "$OSBITS" == "i686" ]]; then @@ -49,4 +49,3 @@ if [ ! -d "$ARDUINO_IDE_PATH" ] || [ ! -f "$ARDUINO_IDE_PATH/arduino-cli" ]; the curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR="$ARDUINO_IDE_PATH" sh fi fi - diff --git a/.github/scripts/install-arduino-core-esp32.sh b/.github/scripts/install-arduino-core-esp32.sh index fe50c909198..e0071a0eb83 100755 --- a/.github/scripts/install-arduino-core-esp32.sh +++ b/.github/scripts/install-arduino-core-esp32.sh @@ -5,7 +5,7 @@ if [ ! -d "$ARDUINO_ESP32_PATH" ]; then echo "Installing ESP32 Arduino Core ..." script_init_path="$PWD" mkdir -p "$ARDUINO_USR_PATH/hardware/espressif" - cd "$ARDUINO_USR_PATH/hardware/espressif" + cd "$ARDUINO_USR_PATH/hardware/espressif" || exit echo "Installing Python Serial ..." pip install pyserial > /dev/null @@ -15,25 +15,25 @@ if [ ! -d "$ARDUINO_ESP32_PATH" ]; then pip install requests > /dev/null fi - if [ ! -z "$GITHUB_REPOSITORY" ]; then + if [ -n "$GITHUB_REPOSITORY" ]; then echo "Linking Core..." - ln -s $GITHUB_WORKSPACE esp32 + ln -s "$GITHUB_WORKSPACE" esp32 else echo "Cloning Core Repository..." git clone https://github.com/espressif/arduino-esp32.git esp32 > /dev/null 2>&1 fi #echo "Updating Submodules ..." - cd esp32 + cd esp32 || exit #git submodule update --init --recursive > /dev/null 2>&1 echo "Installing Platform Tools ..." if [ "$OS_IS_WINDOWS" == "1" ]; then - cd tools && ./get.exe + cd tools && ./get.exe else - cd tools && python get.py + cd tools && python get.py fi - cd $script_init_path + cd "$script_init_path" || exit echo "ESP32 Arduino has been installed in '$ARDUINO_ESP32_PATH'" echo "" diff --git a/.github/scripts/install-arduino-ide.sh b/.github/scripts/install-arduino-ide.sh index 7fd95797834..5b3bcb1791e 100755 --- a/.github/scripts/install-arduino-ide.sh +++ b/.github/scripts/install-arduino-ide.sh @@ -4,7 +4,7 @@ #OSTYPE: 'msys', ARCH: 'x86_64' => win32 #OSTYPE: 'darwin18', ARCH: 'i386' => macos -OSBITS=`uname -m` +OSBITS=$(uname -m) if [[ "$OSTYPE" == "linux"* ]]; then export OS_IS_LINUX="1" ARCHIVE_FORMAT="tar.xz" @@ -77,4 +77,3 @@ if [ ! -d "$ARDUINO_IDE_PATH" ]; then echo "Arduino IDE Installed in '$ARDUINO_IDE_PATH'" echo "" fi - diff --git a/.github/scripts/install-platformio-esp32.sh b/.github/scripts/install-platformio-esp32.sh deleted file mode 100755 index 80c668bdc0e..00000000000 --- a/.github/scripts/install-platformio-esp32.sh +++ /dev/null @@ -1,170 +0,0 @@ -#!/bin/bash - -export PLATFORMIO_ESP32_PATH="$HOME/.platformio/packages/framework-arduinoespressif32" -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" -SDKCONFIG_DIR="$PLATFORMIO_ESP32_PATH/tools/esp32-arduino-libs" -SCRIPTS_DIR="./.github/scripts" -COUNT_SKETCHES="${SCRIPTS_DIR}/sketch_utils.sh count" -CHECK_REQUIREMENTS="${SCRIPTS_DIR}/sketch_utils.sh check_requirements" - -echo "Installing Python Wheel ..." -pip install wheel > /dev/null 2>&1 - -echo "Installing PlatformIO ..." -pip install -U https://github.com/platformio/platformio/archive/master.zip > /dev/null 2>&1 - -echo "Installing Platform ESP32 ..." -python -m platformio platform install $PLATFORMIO_ESP32_URL > /dev/null 2>&1 - -echo "Replacing the package versions ..." -replace_script="import json; import os;" -replace_script+="fp=open(os.path.expanduser('~/.platformio/platforms/espressif32/platform.json'), 'r+');" -replace_script+="data=json.load(fp);" -# Use framework sources from the repository -replace_script+="data['packages']['framework-arduinoespressif32']['version'] = '*';" -replace_script+="del data['packages']['framework-arduinoespressif32']['owner'];" -# Use toolchain packages from the "espressif" organization -replace_script+="data['packages']['toolchain-xtensa-esp32']['owner']='$ESPRESSIF_ORGANIZATION_NAME';" -replace_script+="data['packages']['toolchain-xtensa-esp32s2']['owner']='$ESPRESSIF_ORGANIZATION_NAME';" -replace_script+="data['packages']['toolchain-riscv32-esp']['owner']='$ESPRESSIF_ORGANIZATION_NAME';" -# Update versions to use the upstream -replace_script+="data['packages']['toolchain-xtensa-esp32']['version']='$TOOLCHAIN_VERSION';" -replace_script+="data['packages']['toolchain-xtensa-esp32s2']['version']='$TOOLCHAIN_VERSION';" -replace_script+="data['packages']['toolchain-xtensa-esp32s3']['version']='$TOOLCHAIN_VERSION';" -replace_script+="data['packages']['toolchain-riscv32-esp']['version']='$TOOLCHAIN_VERSION';" -# Add new "framework-arduinoespressif32-libs" package -# Read "package_esp32_index.template.json" to extract a url to a zip package for "esp32-arduino-libs" -replace_script+="fpackage=open(os.path.join('package', 'package_esp32_index.template.json'), 'r+');" -replace_script+="package_data=json.load(fpackage);" -replace_script+="fpackage.close();" -replace_script+="libs_package_archive_url=next(next(system['url'] for system in tool['systems'] if system['host'] == 'x86_64-pc-linux-gnu') for tool in package_data['packages'][0]['tools'] if tool['name'] == 'esp32-arduino-libs');" -replace_script+="data['packages'].update({'framework-arduinoespressif32-libs':{'type':'framework','optional':False,'version':libs_package_archive_url}});" -replace_script+="data['packages']['toolchain-xtensa-esp32'].update({'optional':False});" -# esptool.py may require an upstream version (for now platformio is the owner) -replace_script+="data['packages']['tool-esptoolpy']['version']='$ESPTOOLPY_VERSION';" -# Save results -replace_script+="fp.seek(0);fp.truncate();json.dump(data, fp, indent=2);fp.close()" -python -c "$replace_script" - -if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then - echo "Linking Core..." - ln -s $GITHUB_WORKSPACE "$PLATFORMIO_ESP32_PATH" -else - echo "Cloning Core Repository ..." - git clone --recursive https://github.com/espressif/arduino-esp32.git "$PLATFORMIO_ESP32_PATH" > /dev/null 2>&1 -fi - -echo "PlatformIO for ESP32 has been installed" -echo "" - -function build_pio_sketch(){ # build_pio_sketch - if [ "$#" -lt 3 ]; then - echo "ERROR: Illegal number of parameters" - echo "USAGE: build_pio_sketch " - return 1 - fi - - local board="$1" - local options="$2" - local sketch="$3" - local sketch_dir=$(dirname "$sketch") - echo "" - echo "Compiling '"$(basename "$sketch")"' ..." - python -m platformio ci --board "$board" "$sketch_dir" --project-option="$options" -} - -function build_pio_sketches(){ # build_pio_sketches - if [ "$#" -lt 3 ]; then - echo "ERROR: Illegal number of parameters" - echo "USAGE: build_pio_sketches [ ]" - return 1 - fi - - local board=$1 - local options="$2" - local examples=$3 - local chunk_idex=$4 - local chunks_num=$5 - - if [ "$#" -lt 5 ]; then - chunk_idex="0" - chunks_num="1" - fi - - if [ "$chunks_num" -le 0 ]; then - echo "ERROR: Chunks count must be positive number" - return 1 - fi - if [ "$chunk_idex" -ge "$chunks_num" ]; then - echo "ERROR: Chunk index must be less than chunks count" - return 1 - fi - - set +e - ${COUNT_SKETCHES} "$examples" "esp32" - local sketchcount=$? - set -e - local sketches=$(cat sketches.txt) - rm -rf sketches.txt - - local chunk_size=$(( $sketchcount / $chunks_num )) - local all_chunks=$(( $chunks_num * $chunk_size )) - if [ "$all_chunks" -lt "$sketchcount" ]; then - chunk_size=$(( $chunk_size + 1 )) - fi - - local start_index=$(( $chunk_idex * $chunk_size )) - if [ "$sketchcount" -le "$start_index" ]; then - echo "Skipping job" - return 0 - fi - - local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size )) - if [ "$end_index" -gt "$sketchcount" ]; then - end_index=$sketchcount - fi - - local start_num=$(( $start_index + 1 )) - echo "Found $sketchcount Sketches"; - echo "Chunk Count : $chunks_num" - echo "Chunk Size : $chunk_size" - echo "Start Sketch: $start_num" - echo "End Sketch : $end_index" - - local sketchnum=0 - for sketch in $sketches; do - local sketchdir=$(dirname $sketch) - local sketchdirname=$(basename $sketchdir) - 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 - - local has_requirements=$(${CHECK_REQUIREMENTS} $sketchdir "$SDKCONFIG_DIR/esp32/sdkconfig") - if [ "$has_requirements" == "0" ]; then - continue - fi - fi - - sketchnum=$(($sketchnum + 1)) - if [ "$sketchnum" -le "$start_index" ] \ - || [ "$sketchnum" -gt "$end_index" ]; then - continue - fi - build_pio_sketch "$board" "$options" "$sketch" - local result=$? - if [ $result -ne 0 ]; then - return $result - fi - done - return 0 -} diff --git a/.github/scripts/merge_packages.py b/.github/scripts/merge_packages.py index 96999c17fd7..7e4f47ca8b3 100755 --- a/.github/scripts/merge_packages.py +++ b/.github/scripts/merge_packages.py @@ -1,50 +1,58 @@ #!/usr/bin/env python + # This script merges two Arduino Board Manager package json files. # Usage: # python merge_packages.py package_esp8266com_index.json version/new/package_esp8266com_index.json # Written by Ivan Grokhotkov, 2015 # + from __future__ import print_function -#from distutils.version import LooseVersion + +# from distutils.version import LooseVersion from packaging.version import Version import re import json import sys + def load_package(filename): - pkg = json.load(open(filename))['packages'][0] - print("Loaded package {0} from {1}".format(pkg['name'], filename), file=sys.stderr) - print("{0} platform(s), {1} tools".format(len(pkg['platforms']), len(pkg['tools'])), file=sys.stderr) + pkg = json.load(open(filename))["packages"][0] + print("Loaded package {0} from {1}".format(pkg["name"], filename), file=sys.stderr) + print("{0} platform(s), {1} tools".format(len(pkg["platforms"]), len(pkg["tools"])), file=sys.stderr) return pkg + def merge_objects(versions, obj): for o in obj: - name = o['name'].encode('ascii') - ver = o['version'].encode('ascii') - if not name in versions: + name = o["name"].encode("ascii") + ver = o["version"].encode("ascii") + if name not in versions: print("found new object, {0}".format(name), file=sys.stderr) versions[name] = {} - if not ver in versions[name]: + if ver not in versions[name]: print("found new version {0} for object {1}".format(ver, name), file=sys.stderr) versions[name][ver] = o return versions -# Normalize ESP release version string (x.x.x) by adding '-rc' (x.x.x-rc9223372036854775807) to ensure having REL above any RC -# Dummy approach, functional anyway for current ESP package versioning (unlike NormalizedVersion/LooseVersion/StrictVersion & similar crap) + +# Normalize ESP release version string (x.x.x) by adding '-rc' (x.x.x-rc9223372036854775807) +# to ensure having REL above any RC +# Dummy approach, functional anyway for current ESP package versioning +# (unlike NormalizedVersion/LooseVersion/StrictVersion & similar crap) def pkgVersionNormalized(versionString): verStr = str(versionString) - verParts = re.split('\.|-rc|-alpha', verStr, flags=re.IGNORECASE) - + verParts = re.split(r"\.|-rc|-alpha", verStr, flags=re.IGNORECASE) + if len(verParts) == 3: - if (sys.version_info > (3, 0)): # Python 3 - verStr = str(versionString) + '-rc' + str(sys.maxsize) - else: # Python 2 - verStr = str(versionString) + '-rc' + str(sys.maxint) - + if sys.version_info > (3, 0): # Python 3 + verStr = str(versionString) + "-rc" + str(sys.maxsize) + else: # Python 2 + verStr = str(versionString) + "-rc" + str(sys.maxint) + elif len(verParts) != 4: print("pkgVersionNormalized WARNING: unexpected version format: {0})".format(verStr), file=sys.stderr) - + return verStr @@ -54,31 +62,37 @@ def main(args): return 1 tools = {} - platforms = {} + platforms = {} pkg1 = load_package(args[1]) - tools = merge_objects(tools, pkg1['tools']); - platforms = merge_objects(platforms, pkg1['platforms']); + tools = merge_objects(tools, pkg1["tools"]) + platforms = merge_objects(platforms, pkg1["platforms"]) pkg2 = load_package(args[2]) - tools = merge_objects(tools, pkg2['tools']); - platforms = merge_objects(platforms, pkg2['platforms']); + tools = merge_objects(tools, pkg2["tools"]) + platforms = merge_objects(platforms, pkg2["platforms"]) - pkg1['tools'] = [] - pkg1['platforms'] = [] + pkg1["tools"] = [] + pkg1["platforms"] = [] for name in tools: for version in tools[name]: print("Adding tool {0}-{1}".format(name, version), file=sys.stderr) - pkg1['tools'].append(tools[name][version]) + pkg1["tools"].append(tools[name][version]) for name in platforms: for version in platforms[name]: print("Adding platform {0}-{1}".format(name, version), file=sys.stderr) - pkg1['platforms'].append(platforms[name][version]) - - #pkg1['platforms'] = sorted(pkg1['platforms'], key=lambda k: LooseVersion(pkgVersionNormalized(k['version'])), reverse=True) - pkg1['platforms'] = sorted(pkg1['platforms'], key=lambda k: Version(pkgVersionNormalized(k['version'])), reverse=True) + pkg1["platforms"].append(platforms[name][version]) + + # pkg1["platforms"] = sorted( + # pkg1["platforms"], key=lambda k: LooseVersion(pkgVersionNormalized(k["version"])), reverse=True + # ) + + pkg1["platforms"] = sorted( + pkg1["platforms"], key=lambda k: Version(pkgVersionNormalized(k["version"])), reverse=True + ) + + json.dump({"packages": [pkg1]}, sys.stdout, indent=2) - json.dump({'packages':[pkg1]}, sys.stdout, indent=2) -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main(sys.argv)) diff --git a/.github/scripts/on-pages.sh b/.github/scripts/on-pages.sh index 124518469d2..877d036106b 100755 --- a/.github/scripts/on-pages.sh +++ b/.github/scripts/on-pages.sh @@ -1,12 +1,13 @@ -#/bin/bash +#!/bin/bash + set -e -function get_file_size(){ +function get_file_size { local file="$1" if [[ "$OSTYPE" == "darwin"* ]]; then - eval `stat -s "$file"` + eval "$(stat -s "$file")" local res="$?" - echo "$st_size" + echo "${st_size:?}" return $res else stat --printf="%s" "$file" @@ -15,25 +16,32 @@ function get_file_size(){ } #git_remove_from_pages -function git_remove_from_pages(){ +function git_remove_from_pages { local path=$1 - local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"` - local type=`echo "$info" | jq -r '.type'` - if [ ! $type == "file" ]; then - if [ ! $type == "null" ]; then + local info + local type + local sha + local message + + info=$(curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages") + type=$(echo "$info" | jq -r '.type') + + if [ ! "$type" == "file" ]; then + if [ ! "$type" == "null" ]; then echo "Wrong type '$type'" else echo "File is not on Pages" fi return 0 fi - local sha=`echo "$info" | jq -r '.sha'` - local message="Deleting "$(basename $path) + + sha=$(echo "$info" | jq -r '.sha') + message="Deleting "$(basename "$path") local json="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"sha\":\"$sha\"}" echo "$json" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X DELETE --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path" } -function git_upload_to_pages(){ +function git_upload_to_pages { local path=$1 local src=$2 @@ -42,41 +50,50 @@ function git_upload_to_pages(){ return 1 fi - local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"` - local type=`echo "$info" | jq -r '.type'` - local message=$(basename $path) + local info + local type + local message local sha="" local content="" - if [ $type == "file" ]; then - sha=`echo "$info" | jq -r '.sha'` + info=$(curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages") + type=$(echo "$info" | jq -r '.type') + message=$(basename "$path") + + if [ "$type" == "file" ]; then + sha=$(echo "$info" | jq -r '.sha') sha=",\"sha\":\"$sha\"" message="Updating $message" - elif [ ! $type == "null" ]; then + elif [ ! "$type" == "null" ]; then >&2 echo "Wrong type '$type'" return 1 else message="Creating $message" fi - content=`base64 -i "$src"` + content=$(base64 -i "$src") data="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"content\":\"$content\"$sha}" echo "$data" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X PUT --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path" } -function git_safe_upload_to_pages(){ +function git_safe_upload_to_pages { local path=$1 local file="$2" - local name=$(basename "$file") - local size=`get_file_size "$file"` - local upload_res=`git_upload_to_pages "$path" "$file"` - if [ $? -ne 0 ]; then + local name + local size + local upload_res + + name=$(basename "$file") + size=$(get_file_size "$file") + + if ! upload_res=$(git_upload_to_pages "$path" "$file"); then >&2 echo "ERROR: Failed to upload '$name' ($?)" return 1 fi - up_size=`echo "$upload_res" | jq -r '.content.size'` - if [ $up_size -ne $size ]; then + + up_size=$(echo "$upload_res" | jq -r '.content.size') + if [ "$up_size" -ne "$size" ]; then >&2 echo "ERROR: Uploaded size does not match! $up_size != $size" #git_delete_asset return 1 diff --git a/.github/scripts/on-push.sh b/.github/scripts/on-push.sh index 08ff505f1c0..6095f88e727 100755 --- a/.github/scripts/on-push.sh +++ b/.github/scripts/on-push.sh @@ -4,43 +4,45 @@ set -e export ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp" -function build(){ +function build { local target=$1 local chunk_index=$2 local chunks_cnt=$3 local build_log=$4 - local sketches_file=$5 - shift; shift; shift; shift; shift; - local sketches=$* + local log_level=${5:-none} + local sketches_file=$6 + shift 6 + local sketches=("$@") local BUILD_SKETCH="${SCRIPTS_DIR}/sketch_utils.sh build" local BUILD_SKETCHES="${SCRIPTS_DIR}/sketch_utils.sh chunk_build" - local args="-ai $ARDUINO_IDE_PATH -au $ARDUINO_USR_PATH" - - args+=" -t $target" + local args=("-ai" "$ARDUINO_IDE_PATH" "-au" "$ARDUINO_USR_PATH" "-t" "$target") if [ "$OS_IS_LINUX" == "1" ]; then - args+=" -p $ARDUINO_ESP32_PATH/libraries" - args+=" -i $chunk_index -m $chunks_cnt" + args+=("-p" "$ARDUINO_ESP32_PATH/libraries" "-i" "$chunk_index" "-m" "$chunks_cnt" "-d" "$log_level") if [ -n "$sketches_file" ]; then - args+=" -f $sketches_file" + args+=("-f" "$sketches_file") fi - if [ $build_log -eq 1 ]; then - args+=" -l $build_log" + if [ "$build_log" -eq 1 ]; then + args+=("-l" "$build_log") fi - ${BUILD_SKETCHES} ${args} + ${BUILD_SKETCHES} "${args[@]}" else - for sketch in ${sketches}; do - local sargs="$args -s $(dirname $sketch)" + for sketch in "${sketches[@]}"; do + local sargs=("${args[@]}") + local ctags_version + local preprocessor_version + sargs+=("-s" "$(dirname "$sketch")") if [ "$OS_IS_WINDOWS" == "1" ] && [ -d "$ARDUINO_IDE_PATH/tools-builder" ]; then - local ctags_version=`ls "$ARDUINO_IDE_PATH/tools-builder/ctags/"` - local preprocessor_version=`ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/"` - win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version - -prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version" - sargs+=" ${win_opts}" + ctags_version=$(ls "$ARDUINO_IDE_PATH/tools-builder/ctags/") + preprocessor_version=$(ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/") + sargs+=( + "-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version" + "-prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version" + ) fi - ${BUILD_SKETCH} ${sargs} + ${BUILD_SKETCH} "${sargs[@]}" done fi } @@ -53,15 +55,13 @@ fi CHUNK_INDEX=$1 CHUNKS_CNT=$2 BUILD_LOG=$3 -SKETCHES_FILE=$4 -BUILD_PIO=0 +LOG_LEVEL=$4 +SKETCHES_FILE=$5 if [ "$#" -lt 2 ] || [ "$CHUNKS_CNT" -le 0 ]; then CHUNK_INDEX=0 CHUNKS_CNT=1 elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ] && [ "$CHUNKS_CNT" -ge 2 ]; then CHUNK_INDEX=$CHUNKS_CNT -elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then - BUILD_PIO=1 fi if [ -z "$BUILD_LOG" ] || [ "$BUILD_LOG" -le 0 ]; then @@ -72,54 +72,35 @@ fi #git -C "$GITHUB_WORKSPACE" submodule update --init --recursive > /dev/null 2>&1 SCRIPTS_DIR="./.github/scripts" -if [ "$BUILD_PIO" -eq 0 ]; then - source ${SCRIPTS_DIR}/install-arduino-cli.sh - source ${SCRIPTS_DIR}/install-arduino-core-esp32.sh - - SKETCHES_ESP32="\ - $ARDUINO_ESP32_PATH/libraries/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino\ - $ARDUINO_ESP32_PATH/libraries/BLE/examples/Server/Server.ino\ - $ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino\ - $ARDUINO_ESP32_PATH/libraries/Insights/examples/MinimalDiagnostics/MinimalDiagnostics.ino\ - " - #create sizes_file - sizes_file="$GITHUB_WORKSPACE/cli_compile_$CHUNK_INDEX.json" - - if [ "$BUILD_LOG" -eq 1 ]; then - #create sizes_file and echo start of JSON array with "boards" key - echo "{\"boards\": [" > $sizes_file - fi - - #build sketches for different targets - 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" - build "esp32c6" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32" - build "esp32h2" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32" - build "esp32" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32" - - if [ "$BUILD_LOG" -eq 1 ]; then - #remove last comma from the last JSON object - sed -i '$ s/,$//' "$sizes_file" - #echo end of JSON array - echo "]}" >> $sizes_file - fi -else - source ${SCRIPTS_DIR}/install-platformio-esp32.sh - # PlatformIO ESP32 Test - BOARD="esp32dev" - OPTIONS="board_build.partitions = huge_app.csv" - build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \ - build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \ - build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino" && \ - build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/BLE/examples/Server/Server.ino" && \ - build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino" - - # Basic sanity testing for other series - for board in "esp32-c3-devkitm-1" "esp32-s2-saola-1" "esp32-s3-devkitc-1" - do - python -m platformio ci --board "$board" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient" --project-option="board_build.partitions = huge_app.csv" - done +source "${SCRIPTS_DIR}/install-arduino-cli.sh" +source "${SCRIPTS_DIR}/install-arduino-core-esp32.sh" + +SKETCHES_ESP32=( + "$ARDUINO_ESP32_PATH/libraries/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" + "$ARDUINO_ESP32_PATH/libraries/BLE/examples/Server/Server.ino" + "$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino" + "$ARDUINO_ESP32_PATH/libraries/Insights/examples/MinimalDiagnostics/MinimalDiagnostics.ino" +) +#create sizes_file +sizes_file="$GITHUB_WORKSPACE/cli_compile_$CHUNK_INDEX.json" + +if [ "$BUILD_LOG" -eq 1 ]; then + #create sizes_file and echo start of JSON array with "boards" key + echo "{\"boards\": [" > "$sizes_file" +fi - #build_pio_sketches "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries" +#build sketches for different targets +build "esp32p4" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$LOG_LEVEL" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}" +build "esp32s3" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$LOG_LEVEL" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}" +build "esp32s2" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$LOG_LEVEL" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}" +build "esp32c3" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$LOG_LEVEL" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}" +build "esp32c6" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$LOG_LEVEL" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}" +build "esp32h2" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$LOG_LEVEL" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}" +build "esp32" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$LOG_LEVEL" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}" + +if [ "$BUILD_LOG" -eq 1 ]; then + #remove last comma from the last JSON object + sed -i '$ s/,$//' "$sizes_file" + #echo end of JSON array + echo "]}" >> "$sizes_file" fi diff --git a/.github/scripts/on-release.sh b/.github/scripts/on-release.sh index e0dd7b752c5..242cee93d0b 100755 --- a/.github/scripts/on-release.sh +++ b/.github/scripts/on-release.sh @@ -1,29 +1,34 @@ #!/bin/bash +# Disable shellcheck warning about using 'cat' to read a file. +# Disable shellcheck warning about using individual redirections for each command. +# Disable shellcheck warning about $? uses. +# shellcheck disable=SC2002,SC2129,SC2181,SC2319 -if [ ! $GITHUB_EVENT_NAME == "release" ]; then +if [ ! "$GITHUB_EVENT_NAME" == "release" ]; then echo "Wrong event '$GITHUB_EVENT_NAME'!" exit 1 fi -EVENT_JSON=`cat $GITHUB_EVENT_PATH` +EVENT_JSON=$(cat "$GITHUB_EVENT_PATH") -action=`echo $EVENT_JSON | jq -r '.action'` -if [ ! $action == "published" ]; then +action=$(echo "$EVENT_JSON" | jq -r '.action') +if [ ! "$action" == "published" ]; then echo "Wrong action '$action'. Exiting now..." exit 0 fi -draft=`echo $EVENT_JSON | jq -r '.release.draft'` -if [ $draft == "true" ]; then +draft=$(echo "$EVENT_JSON" | jq -r '.release.draft') +if [ "$draft" == "true" ]; then echo "It's a draft release. Exiting now..." exit 0 fi -RELEASE_PRE=`echo $EVENT_JSON | jq -r '.release.prerelease'` -RELEASE_TAG=`echo $EVENT_JSON | jq -r '.release.tag_name'` -RELEASE_BRANCH=`echo $EVENT_JSON | jq -r '.release.target_commitish'` -RELEASE_ID=`echo $EVENT_JSON | jq -r '.release.id'` +RELEASE_PRE=$(echo "$EVENT_JSON" | jq -r '.release.prerelease') +RELEASE_TAG=$(echo "$EVENT_JSON" | jq -r '.release.tag_name') +RELEASE_BRANCH=$(echo "$EVENT_JSON" | jq -r '.release.target_commitish') +RELEASE_ID=$(echo "$EVENT_JSON" | jq -r '.release.id') +SCRIPTS_DIR="./.github/scripts" OUTPUT_DIR="$GITHUB_WORKSPACE/build" PACKAGE_NAME="esp32-$RELEASE_TAG" PACKAGE_JSON_MERGE="$GITHUB_WORKSPACE/.github/scripts/merge_packages.py" @@ -36,17 +41,23 @@ echo "Action: $action, Branch: $RELEASE_BRANCH, ID: $RELEASE_ID" echo "Tag: $RELEASE_TAG, Draft: $draft, Pre-Release: $RELEASE_PRE" # Try extracting something like a JSON with a "boards" array/element and "vendor" fields -BOARDS=`echo $RELEASE_BODY | grep -Pzo '(?s){.*}' | jq -r '.boards[]? // .boards? // empty' | xargs echo -n 2>/dev/null` -VENDOR=`echo $RELEASE_BODY | grep -Pzo '(?s){.*}' | jq -r '.vendor? // empty' | xargs echo -n 2>/dev/null` -if ! [ -z "${BOARDS}" ]; then echo "Releasing board(s): $BOARDS" ; fi -if ! [ -z "${VENDOR}" ]; then echo "Setting packager: $VENDOR" ; fi +BOARDS=$(echo "$RELEASE_BODY" | grep -Pzo '(?s){.*}' | jq -r '.boards[]? // .boards? // empty' | xargs echo -n 2>/dev/null) +VENDOR=$(echo "$RELEASE_BODY" | grep -Pzo '(?s){.*}' | jq -r '.vendor? // empty' | xargs echo -n 2>/dev/null) -function get_file_size(){ +if [ -n "${BOARDS}" ]; then + echo "Releasing board(s): $BOARDS" +fi + +if [ -n "${VENDOR}" ]; then + echo "Setting packager: $VENDOR" +fi + +function get_file_size { local file="$1" if [[ "$OSTYPE" == "darwin"* ]]; then - eval `stat -s "$file"` + eval "$(stat -s "$file")" local res="$?" - echo "$st_size" + echo "${st_size:?}" return $res else stat --printf="%s" "$file" @@ -54,23 +65,29 @@ function get_file_size(){ fi } -function git_upload_asset(){ - local name=$(basename "$1") +function git_upload_asset { + local name + name=$(basename "$1") # local mime=$(file -b --mime-type "$1") curl -k -X POST -sH "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/octet-stream" --data-binary @"$1" "https://uploads.github.com/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID/assets?name=$name" } -function git_safe_upload_asset(){ +function git_safe_upload_asset { local file="$1" - local name=$(basename "$file") - local size=`get_file_size "$file"` - local upload_res=`git_upload_asset "$file"` - if [ $? -ne 0 ]; then + local name + local size + local upload_res + + name=$(basename "$file") + size=$(get_file_size "$file") + + if ! upload_res=$(git_upload_asset "$file"); then >&2 echo "ERROR: Failed to upload '$name' ($?)" return 1 fi - up_size=`echo "$upload_res" | jq -r '.size'` - if [ $up_size -ne $size ]; then + + up_size=$(echo "$upload_res" | jq -r '.size') + if [ "$up_size" -ne "$size" ]; then >&2 echo "ERROR: Uploaded size does not match! $up_size != $size" #git_delete_asset return 1 @@ -79,7 +96,7 @@ function git_safe_upload_asset(){ return $? } -function git_upload_to_pages(){ +function git_upload_to_pages { local path=$1 local src=$2 @@ -88,41 +105,50 @@ function git_upload_to_pages(){ return 1 fi - local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"` - local type=`echo "$info" | jq -r '.type'` - local message=$(basename $path) + local info + local type + local message local sha="" local content="" - if [ $type == "file" ]; then - sha=`echo "$info" | jq -r '.sha'` + info=$(curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages") + type=$(echo "$info" | jq -r '.type') + message=$(basename "$path") + + if [ "$type" == "file" ]; then + sha=$(echo "$info" | jq -r '.sha') sha=",\"sha\":\"$sha\"" message="Updating $message" - elif [ ! $type == "null" ]; then + elif [ ! "$type" == "null" ]; then >&2 echo "Wrong type '$type'" return 1 else message="Creating $message" fi - content=`base64 -i "$src"` + content=$(base64 -i "$src") data="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"content\":\"$content\"$sha}" echo "$data" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X PUT --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path" } -function git_safe_upload_to_pages(){ +function git_safe_upload_to_pages { local path=$1 local file="$2" - local name=$(basename "$file") - local size=`get_file_size "$file"` - local upload_res=`git_upload_to_pages "$path" "$file"` - if [ $? -ne 0 ]; then + local name + local size + local upload_res + + name=$(basename "$file") + size=$(get_file_size "$file") + + if ! upload_res=$(git_upload_to_pages "$path" "$file"); then >&2 echo "ERROR: Failed to upload '$name' ($?)" return 1 fi - up_size=`echo "$upload_res" | jq -r '.content.size'` - if [ $up_size -ne $size ]; then + + up_size=$(echo "$upload_res" | jq -r '.content.size') + if [ "$up_size" -ne "$size" ]; then >&2 echo "ERROR: Uploaded size does not match! $up_size != $size" #git_delete_asset return 1 @@ -131,15 +157,20 @@ function git_safe_upload_to_pages(){ return $? } -function merge_package_json(){ +function merge_package_json { local jsonLink=$1 local jsonOut=$2 local old_json=$OUTPUT_DIR/oldJson.json local merged_json=$OUTPUT_DIR/mergedJson.json + local error_code=0 echo "Downloading previous JSON $jsonLink ..." curl -L -o "$old_json" "https://github.com/$GITHUB_REPOSITORY/releases/download/$jsonLink?access_token=$GITHUB_TOKEN" 2>/dev/null - if [ $? -ne 0 ]; then echo "ERROR: Download Failed! $?"; exit 1; fi + error_code=$? + if [ $error_code -ne 0 ]; then + echo "ERROR: Download Failed! $error_code" + exit 1 + fi echo "Creating new JSON ..." set +e @@ -147,7 +178,7 @@ function merge_package_json(){ set -e set -v - if [ ! -s $merged_json ]; then + if [ ! -s "$merged_json" ]; then rm -f "$merged_json" echo "Nothing to merge" else @@ -188,9 +219,10 @@ else done # Copy only relevant variant files mkdir "$PKG_DIR/variants/" - for variant in `cat ${PKG_DIR}/boards.txt | grep "\.variant=" | cut -d= -f2` ; do + board_list=$(cat "${PKG_DIR}"/boards.txt | grep "\.variant=" | cut -d= -f2) + while IFS= read -r variant; do cp -Rf "$GITHUB_WORKSPACE/variants/${variant}" "$PKG_DIR/variants/" - done + done <<< "$board_list" fi cp -f "$GITHUB_WORKSPACE/CMakeLists.txt" "$PKG_DIR/" cp -f "$GITHUB_WORKSPACE/idf_component.yml" "$PKG_DIR/" @@ -207,7 +239,7 @@ cp -f "$GITHUB_WORKSPACE/tools/gen_insights_package.py" "$PKG_DIR/tools/" cp -f "$GITHUB_WORKSPACE/tools/gen_insights_package.exe" "$PKG_DIR/tools/" cp -Rf "$GITHUB_WORKSPACE/tools/partitions" "$PKG_DIR/tools/" cp -Rf "$GITHUB_WORKSPACE/tools/ide-debug" "$PKG_DIR/tools/" -cp -f "$GITHUB_WORKSPACE/tools/platformio-build.py" "$PKG_DIR/tools/" +cp -f "$GITHUB_WORKSPACE/tools/pioarduino-build.py" "$PKG_DIR/tools/" # Remove unnecessary files in the package folder echo "Cleaning up folders ..." @@ -219,12 +251,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,40 +261,40 @@ 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' | \ -sed 's/{runtime\.platform\.path}.tools.openocd-esp32/\{runtime.tools.openocd-esp32.path\}/g' \ - > "$PKG_DIR/platform.txt" +sed 's/{runtime\.platform\.path}.tools.openocd-esp32/\{runtime.tools.openocd-esp32.path\}/g' > "$PKG_DIR/platform.txt" -if ! [ -z ${VENDOR} ]; then +if [ -n "${VENDOR}" ]; then # Append vendor name to platform.txt to create a separate section sed -i "/^name=.*/s/$/ ($VENDOR)/" "$PKG_DIR/platform.txt" fi # Add header with version information echo "Generating core_version.h ..." -ver_define=`echo $RELEASE_TAG | tr "[:lower:].\055" "[:upper:]_"` -ver_hex=`git -C "$GITHUB_WORKSPACE" rev-parse --short=8 HEAD 2>/dev/null` -echo \#define ARDUINO_ESP32_GIT_VER 0x$ver_hex > "$PKG_DIR/cores/esp32/core_version.h" -echo \#define ARDUINO_ESP32_GIT_DESC `git -C "$GITHUB_WORKSPACE" describe --tags 2>/dev/null` >> "$PKG_DIR/cores/esp32/core_version.h" -echo \#define ARDUINO_ESP32_RELEASE_$ver_define >> "$PKG_DIR/cores/esp32/core_version.h" -echo \#define ARDUINO_ESP32_RELEASE \"$ver_define\" >> "$PKG_DIR/cores/esp32/core_version.h" +ver_define=$(echo "$RELEASE_TAG" | tr "[:lower:].\055" "[:upper:]_") +ver_hex=$(git -C "$GITHUB_WORKSPACE" rev-parse --short=8 HEAD 2>/dev/null) +echo \#define ARDUINO_ESP32_GIT_VER 0x"$ver_hex" > "$PKG_DIR/cores/esp32/core_version.h" +echo \#define ARDUINO_ESP32_GIT_DESC "$(git -C "$GITHUB_WORKSPACE" describe --tags 2>/dev/null)" >> "$PKG_DIR/cores/esp32/core_version.h" +echo \#define ARDUINO_ESP32_RELEASE_"$ver_define" >> "$PKG_DIR/cores/esp32/core_version.h" +echo \#define ARDUINO_ESP32_RELEASE \""$ver_define"\" >> "$PKG_DIR/cores/esp32/core_version.h" # Compress package folder echo "Creating ZIP ..." pushd "$OUTPUT_DIR" >/dev/null zip -qr "$PACKAGE_ZIP" "$PACKAGE_NAME" -if [ $? -ne 0 ]; then echo "ERROR: Failed to create $PACKAGE_ZIP ($?)"; exit 1; fi +if [ $? -ne 0 ]; then + echo "ERROR: Failed to create $PACKAGE_ZIP ($?)" + exit 1 +fi # Calculate SHA-256 echo "Calculating SHA sum ..." PACKAGE_PATH="$OUTPUT_DIR/$PACKAGE_ZIP" -PACKAGE_SHA=`shasum -a 256 "$PACKAGE_ZIP" | cut -f 1 -d ' '` -PACKAGE_SIZE=`get_file_size "$PACKAGE_ZIP"` +PACKAGE_SHA=$(shasum -a 256 "$PACKAGE_ZIP" | cut -f 1 -d ' ') +PACKAGE_SIZE=$(get_file_size "$PACKAGE_ZIP") popd >/dev/null rm -rf "$PKG_DIR" echo "'$PACKAGE_ZIP' Created! Size: $PACKAGE_SIZE, SHA-256: $PACKAGE_SHA" @@ -274,7 +302,7 @@ echo # Upload package to release page echo "Uploading package to release page ..." -PACKAGE_URL=`git_safe_upload_asset "$PACKAGE_PATH"` +PACKAGE_URL=$(git_safe_upload_asset "$PACKAGE_PATH") echo "Package Uploaded" echo "Download URL: $PACKAGE_URL" echo @@ -282,9 +310,9 @@ echo ## ## TEMP WORKAROUND FOR RV32 LONG PATH ON WINDOWS ## -RVTC_VERSION=`cat $PACKAGE_JSON_TEMPLATE | jq -r ".packages[0].platforms[0].toolsDependencies[] | select(.name == \"$RVTC_NAME\") | .version" | cut -d '_' -f 2` +RVTC_VERSION=$(cat "$PACKAGE_JSON_TEMPLATE" | jq -r ".packages[0].platforms[0].toolsDependencies[] | select(.name == \"$RVTC_NAME\") | .version" | cut -d '_' -f 2) # RVTC_VERSION=`date -j -f '%Y%m%d' "$RVTC_VERSION" '+%y%m'` # MacOS -RVTC_VERSION=`date -d "$RVTC_VERSION" '+%y%m'` +RVTC_VERSION=$(date -d "$RVTC_VERSION" '+%y%m') rvtc_jq_arg="\ (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$RVTC_NAME\")).version = \"$RVTC_VERSION\" |\ (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$RVTC_NAME\")).name = \"$RVTC_NEW_NAME\" |\ @@ -293,15 +321,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-rvfix.json" PACKAGE_JSON_TEMPLATE="$OUTPUT_DIR/package-rvfix.json" @@ -317,17 +337,20 @@ jq_arg=".packages[0].platforms[0].version = \"$RELEASE_TAG\" | \ .packages[0].platforms[0].checksum = \"SHA-256:$PACKAGE_SHA\"" # Generate package JSONs -echo "Genarating $PACKAGE_JSON_DEV ..." +echo "Generating $PACKAGE_JSON_DEV ..." cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV" if [ "$RELEASE_PRE" == "false" ]; then - echo "Genarating $PACKAGE_JSON_REL ..." + echo "Generating $PACKAGE_JSON_REL ..." cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_REL" fi # Figure out the last release or pre-release echo "Getting previous releases ..." -releasesJson=`curl -sH "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$GITHUB_REPOSITORY/releases" 2>/dev/null` -if [ $? -ne 0 ]; then echo "ERROR: Get Releases Failed! ($?)"; exit 1; fi +releasesJson=$(curl -sH "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$GITHUB_REPOSITORY/releases" 2>/dev/null) +if [ $? -ne 0 ]; then + echo "ERROR: Get Releases Failed! ($?)" + exit 1 +fi set +e prev_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false)) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name") @@ -347,13 +370,13 @@ echo "Previous (any)release: $prev_any_release" echo # Merge package JSONs with previous releases -if [ ! -z "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then +if [ -n "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then echo "Merging with JSON from $prev_any_release ..." merge_package_json "$prev_any_release/$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV" fi if [ "$RELEASE_PRE" == "false" ]; then - if [ ! -z "$prev_release" ] && [ "$prev_release" != "null" ]; then + if [ -n "$prev_release" ] && [ "$prev_release" != "null" ]; then echo "Merging with JSON from $prev_release ..." merge_package_json "$prev_release/$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL" fi @@ -363,21 +386,30 @@ fi echo "Installing arduino-cli ..." export PATH="/home/runner/bin:$PATH" -source ./.github/scripts/install-arduino-cli.sh +source "${SCRIPTS_DIR}/install-arduino-cli.sh" echo "Testing $PACKAGE_JSON_DEV install ..." echo "Installing esp32 ..." arduino-cli core install esp32:esp32 --additional-urls "file://$OUTPUT_DIR/$PACKAGE_JSON_DEV" -if [ $? -ne 0 ]; then echo "ERROR: Failed to install esp32 ($?)"; exit 1; fi +if [ $? -ne 0 ]; then + echo "ERROR: Failed to install esp32 ($?)" + exit 1 +fi echo "Compiling example ..." -arduino-cli compile --fqbn esp32:esp32:esp32 $GITHUB_WORKSPACE/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino -if [ $? -ne 0 ]; then echo "ERROR: Failed to compile example ($?)"; exit 1; fi +arduino-cli compile --fqbn esp32:esp32:esp32 "$GITHUB_WORKSPACE"/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino +if [ $? -ne 0 ]; then + echo "ERROR: Failed to compile example ($?)" + exit 1 +fi echo "Uninstalling esp32 ..." arduino-cli core uninstall esp32:esp32 -if [ $? -ne 0 ]; then echo "ERROR: Failed to uninstall esp32 ($?)"; exit 1; fi +if [ $? -ne 0 ]; then + echo "ERROR: Failed to uninstall esp32 ($?)" + exit 1 +fi echo "Test successful!" @@ -386,15 +418,24 @@ if [ "$RELEASE_PRE" == "false" ]; then echo "Installing esp32 ..." arduino-cli core install esp32:esp32 --additional-urls "file://$OUTPUT_DIR/$PACKAGE_JSON_REL" - if [ $? -ne 0 ]; then echo "ERROR: Failed to install esp32 ($?)"; exit 1; fi + if [ $? -ne 0 ]; then + echo "ERROR: Failed to install esp32 ($?)" + exit 1 + fi echo "Compiling example ..." - arduino-cli compile --fqbn esp32:esp32:esp32 $GITHUB_WORKSPACE/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino - if [ $? -ne 0 ]; then echo "ERROR: Failed to compile example ($?)"; exit 1; fi + arduino-cli compile --fqbn esp32:esp32:esp32 "$GITHUB_WORKSPACE"/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino + if [ $? -ne 0 ]; then + echo "ERROR: Failed to compile example ($?)" + exit 1 + fi echo "Uninstalling esp32 ..." arduino-cli core uninstall esp32:esp32 - if [ $? -ne 0 ]; then echo "ERROR: Failed to uninstall esp32 ($?)"; exit 1; fi + if [ $? -ne 0 ]; then + echo "ERROR: Failed to uninstall esp32 ($?)" + exit 1 + fi echo "Test successful!" fi @@ -402,13 +443,13 @@ fi # Upload package JSONs echo "Uploading $PACKAGE_JSON_DEV ..." -echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV"` -echo "Pages URL: "`git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV"` +echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV")" +echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV")" echo if [ "$RELEASE_PRE" == "false" ]; then echo "Uploading $PACKAGE_JSON_REL ..." - echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL"` - echo "Pages URL: "`git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL"` + echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL")" + echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL")" echo fi diff --git a/.github/scripts/set_push_chunks.sh b/.github/scripts/set_push_chunks.sh index 11a93a7159d..ff0af7da6e8 100644 --- a/.github/scripts/set_push_chunks.sh +++ b/.github/scripts/set_push_chunks.sh @@ -11,23 +11,23 @@ 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) " + 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) " + 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}') + 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" @@ -36,14 +36,14 @@ elif [[ $LIB_CHANGED == 'true' ]]; 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) + 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) + sketch=$(find "$(dirname "$file")" -name '*.ino') sketches+="$sketch " echo "Sketch in example folder: $sketch" fi @@ -53,9 +53,9 @@ fi if [[ -n $sketches ]]; then # Remove duplicates - sketches=$(echo $sketches | tr ' ' '\n' | sort | uniq) + sketches=$(echo "$sketches" | tr ' ' '\n' | sort | uniq) for sketch in $sketches; do - echo $sketch >> sketches_found.txt + echo "$sketch" >> sketches_found.txt chunks_count=$((chunks_count+1)) done echo "Number of sketches found: $chunks_count" @@ -69,15 +69,16 @@ if [[ -n $sketches ]]; then fi chunks='["0"' -for i in $(seq 1 $(( $chunks_count - 1 )) ); do +for i in $(seq 1 $(( chunks_count - 1 )) ); do chunks+=",\"$i\"" done chunks+="]" -echo "build_all=$build_all" >> $GITHUB_OUTPUT -echo "build_libraries=$BUILD_LIBRARIES" >> $GITHUB_OUTPUT -echo "build_static_sketches=$BUILD_STATIC_SKETCHES" >> $GITHUB_OUTPUT -echo "build_idf=$BUILD_IDF" >> $GITHUB_OUTPUT -echo "build_platformio=$BUILD_PLATFORMIO" >> $GITHUB_OUTPUT -echo "chunk_count=$chunks_count" >> $GITHUB_OUTPUT -echo "chunks=$chunks" >> $GITHUB_OUTPUT +{ + echo "build_all=$build_all" + echo "build_libraries=$BUILD_LIBRARIES" + echo "build_static_sketches=$BUILD_STATIC_SKETCHES" + echo "build_idf=$BUILD_IDF" + echo "chunk_count=$chunks_count" + echo "chunks=$chunks" +} >> "$GITHUB_OUTPUT" diff --git a/.github/scripts/sketch_utils.sh b/.github/scripts/sketch_utils.sh index e2b2ec0b269..00d7d1bc232 100755 --- a/.github/scripts/sketch_utils.sh +++ b/.github/scripts/sketch_utils.sh @@ -8,10 +8,12 @@ else SDKCONFIG_DIR="tools/esp32-arduino-libs" fi -function check_requirements(){ # check_requirements +function check_requirements { # check_requirements local sketchdir=$1 local sdkconfig_path=$2 local has_requirements=1 + local requirements + local requirements_or if [ ! -f "$sdkconfig_path" ] || [ ! -f "$sketchdir/ci.json" ]; then echo "ERROR: sdkconfig or ci.json not found" 1>&2 @@ -19,10 +21,10 @@ function check_requirements(){ # check_requirements # CI will fail and the user will know that the sketch has a problem. else # Check if the sketch requires any configuration options (AND) - local requirements=$(jq -r '.requires[]? // empty' "$sketchdir/ci.json") + requirements=$(jq -r '.requires[]? // empty' "$sketchdir/ci.json") if [[ "$requirements" != "null" && "$requirements" != "" ]]; then for requirement in $requirements; do - requirement=$(echo $requirement | xargs) + requirement=$(echo "$requirement" | xargs) found_line=$(grep -E "^$requirement" "$sdkconfig_path") if [[ "$found_line" == "" ]]; then has_requirements=0 @@ -31,11 +33,11 @@ function check_requirements(){ # check_requirements fi # Check if the sketch requires any configuration options (OR) - local requirements_or=$(jq -r '.requires_any[]? // empty' "$sketchdir/ci.json") + requirements_or=$(jq -r '.requires_any[]? // empty' "$sketchdir/ci.json") if [[ "$requirements_or" != "null" && "$requirements_or" != "" ]]; then local found=false for requirement in $requirements_or; do - requirement=$(echo $requirement | xargs) + requirement=$(echo "$requirement" | xargs) found_line=$(grep -E "^$requirement" "$sdkconfig_path") if [[ "$found_line" != "" ]]; then found=true @@ -51,8 +53,8 @@ function check_requirements(){ # check_requirements echo $has_requirements } -function build_sketch(){ # build_sketch [extra-options] - while [ ! -z "$1" ]; do +function build_sketch { # build_sketch [extra-options] + while [ -n "$1" ]; do case "$1" in -ai ) shift @@ -97,10 +99,10 @@ function build_sketch(){ # build_sketch [ex shift done - xtra_opts=$* + xtra_opts=("$@") len=0 - if [ -z $sketchdir ]; then + if [ -z "$sketchdir" ]; then echo "ERROR: Sketch directory not provided" echo "$USAGE" exit 1 @@ -108,8 +110,8 @@ function build_sketch(){ # build_sketch [ex # No FQBN was passed, try to get it from other options - if [ -z $fqbn ]; then - if [ -z $target ]; then + if [ -z "$fqbn" ]; then + if [ -z "$target" ]; then echo "ERROR: Unspecified chip" echo "$USAGE" exit 1 @@ -120,25 +122,25 @@ function build_sketch(){ # build_sketch [ex # precedence. Note that the following logic also falls to the default # parameters if no arguments were passed and no file was found. - if [ -z $options ] && [ -f $sketchdir/ci.json ]; then + if [ -z "$options" ] && [ -f "$sketchdir"/ci.json ]; then # The config file could contain multiple FQBNs for one chip. If # that's the case we build one time for every FQBN. - len=`jq -r --arg target $target '.fqbn[$target] | length' $sketchdir/ci.json` - if [ $len -gt 0 ]; then - fqbn=`jq -r --arg target $target '.fqbn[$target] | sort' $sketchdir/ci.json` + len=$(jq -r --arg target "$target" '.fqbn[$target] | length' "$sketchdir"/ci.json) + if [ "$len" -gt 0 ]; then + fqbn=$(jq -r --arg target "$target" '.fqbn[$target] | sort' "$sketchdir"/ci.json) fi fi - if [ ! -z $options ] || [ $len -eq 0 ]; then + if [ -n "$options" ] || [ "$len" -eq 0 ]; then # Since we are passing options, we will end up with only one FQBN to # build. len=1 - if [ -f $sketchdir/ci.json ]; then - fqbn_append=`jq -r '.fqbn_append' $sketchdir/ci.json` - if [ $fqbn_append == "null" ]; then + if [ -f "$sketchdir"/ci.json ]; then + fqbn_append=$(jq -r '.fqbn_append' "$sketchdir"/ci.json) + if [ "$fqbn_append" == "null" ]; then fqbn_append="" fi fi @@ -153,6 +155,7 @@ function build_sketch(){ # build_sketch [ex esp32c3_opts=$(echo "$debug_level,$fqbn_append" | sed 's/^,*//;s/,*$//;s/,\{2,\}/,/g') esp32c6_opts=$(echo "$debug_level,$fqbn_append" | sed 's/^,*//;s/,*$//;s/,\{2,\}/,/g') esp32h2_opts=$(echo "$debug_level,$fqbn_append" | sed 's/^,*//;s/,*$//;s/,\{2,\}/,/g') + esp32p4_opts=$(echo "PSRAM=enabled,USBMode=default,$debug_level,$fqbn_append" | sed 's/^,*//;s/,*$//;s/,\{2,\}/,/g') # Select the common part of the FQBN based on the target. The rest will be # appended depending on the passed options. @@ -184,6 +187,14 @@ function build_sketch(){ # build_sketch [ex [ -n "${options:-$esp32h2_opts}" ] && opt=":${options:-$esp32h2_opts}" fqbn="espressif:esp32:esp32h2$opt" ;; + "esp32p4") + [ -n "${options:-$esp32p4_opts}" ] && opt=":${options:-$esp32p4_opts}" + fqbn="espressif:esp32:esp32p4$opt" + ;; + *) + echo "ERROR: Invalid chip: $target" + exit 1 + ;; esac # Make it look like a JSON array. @@ -202,7 +213,7 @@ function build_sketch(){ # build_sketch [ex exit 1 fi - # The directory that will hold all the artifcats (the build directory) is + # The directory that will hold all the artifacts (the build directory) is # provided through: # 1. An env variable called ARDUINO_BUILD_DIR. # 2. Created at the sketch level as "build" in the case of a single @@ -210,17 +221,18 @@ function build_sketch(){ # build_sketch [ex # 3. Created at the sketch level as "buildX" where X is the number # of configuration built in case of a multiconfiguration test. - sketchname=$(basename $sketchdir) + sketchname=$(basename "$sketchdir") + local has_requirements - if [ -f $sketchdir/ci.json ]; then + 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) + is_target=$(jq -r --arg target "$target" '.targets[$target]' "$sketchdir"/ci.json) if [[ "$is_target" == "false" ]]; then echo "Skipping $sketchname for target $target" exit 0 fi - local has_requirements=$(check_requirements "$sketchdir" "$SDKCONFIG_DIR/$target/sdkconfig") + has_requirements=$(check_requirements "$sketchdir" "$SDKCONFIG_DIR/$target/sdkconfig") if [ "$has_requirements" == "0" ]; then echo "Target $target does not meet the requirements for $sketchname. Skipping." exit 0 @@ -230,7 +242,7 @@ function build_sketch(){ # build_sketch [ex ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp" if [ -n "$ARDUINO_BUILD_DIR" ]; then build_dir="$ARDUINO_BUILD_DIR" - elif [ $len -eq 1 ]; then + elif [ "$len" -eq 1 ]; then # build_dir="$sketchdir/build" build_dir="$HOME/.arduino/tests/$sketchname/build.tmp" fi @@ -239,51 +251,49 @@ function build_sketch(){ # build_sketch [ex sizes_file="$GITHUB_WORKSPACE/cli_compile_$chunk_index.json" mkdir -p "$ARDUINO_CACHE_DIR" - for i in `seq 0 $(($len - 1))` - do - if [ $len -ne 1 ]; then - # build_dir="$sketchdir/build$i" - build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp" + for i in $(seq 0 $((len - 1))); do + if [ "$len" -ne 1 ]; then + # build_dir="$sketchdir/build$i" + build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp" fi - rm -rf $build_dir - mkdir -p $build_dir + rm -rf "$build_dir" + mkdir -p "$build_dir" - currfqbn=`echo $fqbn | jq -r --argjson i $i '.[$i]'` + currfqbn=$(echo "$fqbn" | jq -r --argjson i "$i" '.[$i]') if [ -f "$ide_path/arduino-cli" ]; then echo "Building $sketchname with arduino-cli and FQBN=$currfqbn" - curroptions=`echo "$currfqbn" | cut -d':' -f4` - currfqbn=`echo "$currfqbn" | cut -d':' -f1-3` - $ide_path/arduino-cli compile \ + curroptions=$(echo "$currfqbn" | cut -d':' -f4) + currfqbn=$(echo "$currfqbn" | cut -d':' -f1-3) + "$ide_path"/arduino-cli compile \ --fqbn "$currfqbn" \ --board-options "$curroptions" \ --warnings "all" \ --build-property "compiler.warning_flags.all=-Wall -Werror=all -Wextra" \ - --build-cache-path "$ARDUINO_CACHE_DIR" \ --build-path "$build_dir" \ - $xtra_opts "${sketchdir}" \ - 2>&1 | tee $output_file + "${xtra_opts[@]}" "${sketchdir}" \ + 2>&1 | tee "$output_file" exit_status=${PIPESTATUS[0]} - if [ $exit_status -ne 0 ]; then + if [ "$exit_status" -ne 0 ]; then echo "ERROR: Compilation failed with error code $exit_status" - exit $exit_status + exit "$exit_status" fi - if [ $log_compilation ]; then + if [ -n "$log_compilation" ]; then #Extract the program storage space and dynamic memory usage in bytes and percentage in separate variables from the output, just the value without the string - flash_bytes=$(grep -oE 'Sketch uses ([0-9]+) bytes' $output_file | awk '{print $3}') - flash_percentage=$(grep -oE 'Sketch uses ([0-9]+) bytes \(([0-9]+)%\)' $output_file | awk '{print $5}' | tr -d '(%)') - ram_bytes=$(grep -oE 'Global variables use ([0-9]+) bytes' $output_file | awk '{print $4}') - ram_percentage=$(grep -oE 'Global variables use ([0-9]+) bytes \(([0-9]+)%\)' $output_file | awk '{print $6}' | tr -d '(%)') + flash_bytes=$(grep -oE 'Sketch uses ([0-9]+) bytes' "$output_file" | awk '{print $3}') + flash_percentage=$(grep -oE 'Sketch uses ([0-9]+) bytes \(([0-9]+)%\)' "$output_file" | awk '{print $5}' | tr -d '(%)') + ram_bytes=$(grep -oE 'Global variables use ([0-9]+) bytes' "$output_file" | awk '{print $4}') + ram_percentage=$(grep -oE 'Global variables use ([0-9]+) bytes \(([0-9]+)%\)' "$output_file" | awk '{print $6}' | tr -d '(%)') # Extract the directory path excluding the filename directory_path=$(dirname "$sketch") # Define the constant part constant_part="/home/runner/Arduino/hardware/espressif/esp32/libraries/" - # Extract the desired substring using sed - lib_sketch_name=$(echo "$directory_path" | sed "s|$constant_part||") + # Extract the desired substring + lib_sketch_name="${directory_path#"$constant_part"}" #append json file where key is fqbn, sketch name, sizes -> extracted values echo "{\"name\": \"$lib_sketch_name\", \"sizes\": [{ @@ -299,15 +309,15 @@ function build_sketch(){ # build_sketch [ex echo "Building $sketchname with arduino-builder and FQBN=$currfqbn" echo "Build path = $build_dir" - $ide_path/arduino-builder -compile -logger=human -core-api-version=10810 \ - -fqbn=\"$currfqbn\" \ + "$ide_path"/arduino-builder -compile -logger=human -core-api-version=10810 \ + -fqbn=\""$currfqbn"\" \ -warnings="all" \ -tools "$ide_path/tools-builder" \ -hardware "$user_path/hardware" \ -libraries "$user_path/libraries" \ -build-cache "$ARDUINO_CACHE_DIR" \ -build-path "$build_dir" \ - $xtra_opts "${sketchdir}/${sketchname}.ino" + "${xtra_opts[@]}" "${sketchdir}/${sketchname}.ino" exit_status=$? if [ $exit_status -ne 0 ]; then @@ -334,15 +344,16 @@ function build_sketch(){ # build_sketch [ex unset options } -function count_sketches(){ # count_sketches [target] [file] [ignore-requirements] +function count_sketches { # count_sketches [target] [file] [ignore-requirements] local path=$1 local target=$2 local ignore_requirements=$3 local file=$4 + local sketches if [ $# -lt 1 ]; then - echo "ERROR: Illegal number of parameters" - echo "USAGE: ${0} count [target]" + echo "ERROR: Illegal number of parameters" + echo "USAGE: ${0} count [target]" fi rm -rf sketches.txt @@ -352,42 +363,47 @@ function count_sketches(){ # count_sketches [target] [file] [ignore-requi fi if [ -f "$file" ]; then - local sketches=$(cat $file) + sketches=$(cat "$file") else - local sketches=$(find $path -name *.ino | sort) + sketches=$(find "$path" -name '*.ino' | sort) fi local sketchnum=0 for sketch in $sketches; do - local sketchdir=$(dirname $sketch) - local sketchdirname=$(basename $sketchdir) - local sketchname=$(basename $sketch) + local sketchdir + local sketchdirname + local sketchname + local has_requirements + + sketchdir=$(dirname "$sketch") + sketchdirname=$(basename "$sketchdir") + sketchname=$(basename "$sketch") + if [[ "$sketchdirname.ino" != "$sketchname" ]]; then continue elif [[ -n $target ]] && [[ -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) + is_target=$(jq -r --arg target "$target" '.targets[$target]' "$sketchdir"/ci.json) if [[ "$is_target" == "false" ]]; then continue fi if [ "$ignore_requirements" != "1" ]; then - local has_requirements=$(check_requirements "$sketchdir" "$SDKCONFIG_DIR/$target/sdkconfig") + has_requirements=$(check_requirements "$sketchdir" "$SDKCONFIG_DIR/$target/sdkconfig") if [ "$has_requirements" == "0" ]; then continue fi fi fi - echo $sketch >> sketches.txt - sketchnum=$(($sketchnum + 1)) + echo "$sketch" >> sketches.txt + sketchnum=$((sketchnum + 1)) done return $sketchnum } -function build_sketches(){ # build_sketches [extra-options] - - local args="" - while [ ! -z "$1" ]; do +function build_sketches { # build_sketches [extra-options] + local args=() + while [ -n "$1" ]; do case $1 in -ai ) shift @@ -400,12 +416,12 @@ function build_sketches(){ # build_sketches 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 +{ + echo "build-types=[$build_types]" + echo "hw-types=[$hw_types]" + echo "wokwi-types=[$wokwi_types]" + echo "qemu-types=[$qemu_types]" + echo "targets=[$targets]" +} >> "$GITHUB_OUTPUT" diff --git a/.github/scripts/tests_run.sh b/.github/scripts/tests_run.sh index 16b0f2fb500..513fd16b371 100755 --- a/.github/scripts/tests_run.sh +++ b/.github/scripts/tests_run.sh @@ -1,126 +1,130 @@ #!/bin/bash -function run_test() { +function run_test { local target=$1 local sketch=$2 local options=$3 local erase_flash=$4 - local sketchdir=$(dirname $sketch) - local sketchname=$(basename $sketchdir) + local sketchdir + local sketchname local result=0 local error=0 local sdkconfig_path + local extra_args - if [ $options -eq 0 ] && [ -f $sketchdir/ci.json ]; then - len=`jq -r --arg target $target '.fqbn[$target] | length' $sketchdir/ci.json` - if [ $len -eq 0 ]; then + sketchdir=$(dirname "$sketch") + sketchname=$(basename "$sketchdir") + + if [ "$options" -eq 0 ] && [ -f "$sketchdir"/ci.json ]; then + len=$(jq -r --arg target "$target" '.fqbn[$target] | length' "$sketchdir"/ci.json) + if [ "$len" -eq 0 ]; then len=1 fi else len=1 fi - if [ $len -eq 1 ]; then + if [ "$len" -eq 1 ]; then sdkconfig_path="$HOME/.arduino/tests/$sketchname/build.tmp/sdkconfig" else sdkconfig_path="$HOME/.arduino/tests/$sketchname/build0.tmp/sdkconfig" fi - if [ -f $sketchdir/ci.json ]; then + 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) + is_target=$(jq -r --arg target "$target" '.targets[$target]' "$sketchdir"/ci.json) + selected_platform=$(jq -r --arg platform "$platform" '.platforms[$platform]' "$sketchdir"/ci.json) if [[ $is_target == "false" ]] || [[ $selected_platform == "false" ]]; then - printf "\033[93mSkipping $sketchname test for $target, platform: $platform\033[0m\n" + printf "\033[93mSkipping %s test for %s, platform: %s\033[0m\n" "$sketchname" "$target" "$platform" printf "\n\n\n" return 0 fi fi - if [ ! -f $sdkconfig_path ]; then - printf "\033[93mSketch $sketchname not built\nMight be due to missing target requirements or build failure\033[0m\n" + if [ ! -f "$sdkconfig_path" ]; then + printf "\033[93mSketch %s not built\nMight be due to missing target requirements or build failure\033[0m\n" "$sketchname" printf "\n\n\n" return 0 fi - local right_target=$(grep -E "^CONFIG_IDF_TARGET=\"$target\"$" "$sdkconfig_path") + local right_target + right_target=$(grep -E "^CONFIG_IDF_TARGET=\"$target\"$" "$sdkconfig_path") if [ -z "$right_target" ]; then - printf "\033[91mError: Sketch $sketchname compiled for different target\n\033[0m\n" + printf "\033[91mError: Sketch %s compiled for different target\n\033[0m\n" "$sketchname" printf "\n\n\n" return 1 fi - if [ $len -eq 1 ]; then - # build_dir="$sketchdir/build" - build_dir="$HOME/.arduino/tests/$sketchname/build.tmp" - report_file="$sketchdir/$target/$sketchname.xml" + if [ "$len" -eq 1 ]; then + # build_dir="$sketchdir/build" + build_dir="$HOME/.arduino/tests/$sketchname/build.tmp" + report_file="$sketchdir/$target/$sketchname.xml" fi - for i in `seq 0 $(($len - 1))` - do + for i in $(seq 0 $((len - 1))); do fqbn="Default" - if [ $len -ne 1 ]; then - fqbn=`jq -r --arg target $target --argjson i $i '.fqbn[$target] | sort | .[$i]' $sketchdir/ci.json` - elif [ -f $sketchdir/ci.json ]; then - has_fqbn=`jq -r --arg target $target '.fqbn[$target]' $sketchdir/ci.json` + if [ "$len" -ne 1 ]; then + fqbn=$(jq -r --arg target "$target" --argjson i "$i" '.fqbn[$target] | sort | .[$i]' "$sketchdir"/ci.json) + elif [ -f "$sketchdir"/ci.json ]; then + has_fqbn=$(jq -r --arg target "$target" '.fqbn[$target]' "$sketchdir"/ci.json) if [ "$has_fqbn" != "null" ]; then - fqbn=`jq -r --arg target $target '.fqbn[$target] | .[0]' $sketchdir/ci.json` + fqbn=$(jq -r --arg target "$target" '.fqbn[$target] | .[0]' "$sketchdir"/ci.json) fi fi - printf "\033[95mRunning test: $sketchname -- Config: $fqbn\033[0m\n" - if [ $erase_flash -eq 1 ]; then - esptool.py -c $target erase_flash + printf "\033[95mRunning test: %s -- Config: %s\033[0m\n" "$sketchname" "$fqbn" + if [ "$erase_flash" -eq 1 ]; then + esptool.py -c "$target" erase_flash fi - if [ $len -ne 1 ]; then + if [ "$len" -ne 1 ]; then # build_dir="$sketchdir/build$i" build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp" report_file="$sketchdir/$target/$sketchname$i.xml" fi if [ $platform == "wokwi" ]; then - extra_args="--target $target --embedded-services arduino,wokwi --wokwi-timeout=$wokwi_timeout" + extra_args=("--target" "$target" "--embedded-services" "arduino,wokwi" "--wokwi-timeout=$wokwi_timeout") if [[ -f "$sketchdir/scenario.yaml" ]]; then - extra_args+=" --wokwi-scenario $sketchdir/scenario.yaml" + extra_args+=("--wokwi-scenario" "$sketchdir/scenario.yaml") fi if [[ -f "$sketchdir/diagram.$target.json" ]]; then - extra_args+=" --wokwi-diagram $sketchdir/diagram.$target.json" + extra_args+=("--wokwi-diagram" "$sketchdir/diagram.$target.json") fi elif [ $platform == "qemu" ]; then PATH=$HOME/qemu/bin:$PATH - extra_args="--embedded-services qemu --qemu-image-path $build_dir/$sketchname.ino.merged.bin" + extra_args=("--embedded-services" "qemu" "--qemu-image-path" "$build_dir/$sketchname.ino.merged.bin") - if [ $target == "esp32" ] || [ $target == "esp32s3" ]; then - extra_args+=" --qemu-prog-path qemu-system-xtensa --qemu-cli-args=\"-machine $target -m 4M -nographic\"" - elif [ $target == "esp32c3" ]; then - extra_args+=" --qemu-prog-path qemu-system-riscv32 --qemu-cli-args=\"-machine $target -icount 3 -nographic\"" + if [ "$target" == "esp32" ] || [ "$target" == "esp32s3" ]; then + extra_args+=("--qemu-prog-path" "qemu-system-xtensa" "--qemu-cli-args=\"-machine $target -m 4M -nographic\"") + elif [ "$target" == "esp32c3" ]; then + extra_args+=("--qemu-prog-path" "qemu-system-riscv32" "--qemu-cli-args=\"-machine $target -icount 3 -nographic\"") else - printf "\033[91mUnsupported QEMU target: $target\033[0m\n" + printf "\033[91mUnsupported QEMU target: %s\033[0m\n" "$target" exit 1 fi else - extra_args="--embedded-services esp,arduino" + extra_args=("--embedded-services" "esp,arduino") fi - rm $sketchdir/diagram.json 2>/dev/null || true + rm "$sketchdir"/diagram.json 2>/dev/null || true result=0 - printf "\033[95mpytest $sketchdir/test_$sketchname.py --build-dir $build_dir --junit-xml=$report_file $extra_args\033[0m\n" - bash -c "set +e; pytest $sketchdir/test_$sketchname.py --build-dir $build_dir --junit-xml=$report_file $extra_args; exit \$?" || result=$? + printf "\033[95mpytest \"%s/test_%s.py\" --build-dir \"%s\" --junit-xml=\"%s\" %s\033[0m\n" "$sketchdir" "$sketchname" "$build_dir" "$report_file" "${extra_args[*]@Q}" + bash -c "set +e; pytest \"$sketchdir/test_$sketchname.py\" --build-dir \"$build_dir\" --junit-xml=\"$report_file\" ${extra_args[*]@Q}; exit \$?" || result=$? printf "\n" if [ $result -ne 0 ]; then result=0 - printf "\033[95mRetrying test: $sketchname -- Config: $i\033[0m\n" - printf "\033[95mpytest $sketchdir/test_$sketchname.py --build-dir $build_dir --junit-xml=$report_file $extra_args\033[0m\n" - bash -c "set +e; pytest $sketchdir/test_$sketchname.py --build-dir $build_dir --junit-xml=$report_file $extra_args; exit \$?" || result=$? + printf "\033[95mRetrying test: %s -- Config: %s\033[0m\n" "$sketchname" "$i" + printf "\033[95mpytest \"%s/test_%s.py\" --build-dir \"%s\" --junit-xml=\"%s\" %s\033[0m\n" "$sketchdir" "$sketchname" "$build_dir" "$report_file" "${extra_args[*]@Q}" + bash -c "set +e; pytest \"$sketchdir/test_$sketchname.py\" --build-dir \"$build_dir\" --junit-xml=\"$report_file\" ${extra_args[*]@Q}; exit \$?" || result=$? printf "\n" if [ $result -ne 0 ]; then - printf "\033[91mFailed test: $sketchname -- Config: $i\033[0m\n\n" - error=$result + printf "\033[91mFailed test: %s -- Config: %s\033[0m\n\n" "$sketchname" "$i" + error=$result fi fi done @@ -136,13 +140,13 @@ chunk_run=0 options=0 erase=0 -while [ ! -z "$1" ]; do +while [ -n "$1" ]; do case $1 in -c ) chunk_run=1 ;; -Q ) - if [ ! -d $QEMU_PATH ]; then + if [ ! -d "$QEMU_PATH" ]; then echo "QEMU path $QEMU_PATH does not exist" exit 1 fi @@ -188,98 +192,97 @@ while [ ! -z "$1" ]; do test_type=$1 ;; * ) - break - ;; + break + ;; esac shift done if [ ! $platform == "qemu" ]; then - source ${SCRIPTS_DIR}/install-arduino-ide.sh + source "${SCRIPTS_DIR}/install-arduino-ide.sh" fi # If sketch is provided and test type is not, test type is inferred from the sketch path if [[ $test_type == "all" ]] || [[ -z $test_type ]]; then if [ -n "$sketch" ]; then - tmp_sketch_path=$(find tests -name $sketch.ino) - test_type=$(basename $(dirname $(dirname "$tmp_sketch_path"))) + tmp_sketch_path=$(find tests -name "$sketch".ino) + test_type=$(basename "$(dirname "$(dirname "$tmp_sketch_path")")") echo "Sketch $sketch test type: $test_type" test_folder="$PWD/tests/$test_type" else - test_folder="$PWD/tests" + test_folder="$PWD/tests" fi else test_folder="$PWD/tests/$test_type" fi if [ $chunk_run -eq 0 ]; then - if [ -z $sketch ]; then + if [ -z "$sketch" ]; then echo "ERROR: Sketch name is required for single test run" exit 1 fi - run_test $target $test_folder/$sketch/$sketch.ino $options $erase + run_test "$target" "$test_folder"/"$sketch"/"$sketch".ino $options $erase exit $? else - if [ "$chunk_max" -le 0 ]; then - echo "ERROR: Chunks count must be positive number" - exit 1 - fi - - if [ "$chunk_index" -ge "$chunk_max" ] && [ "$chunk_max" -ge 2 ]; then - echo "ERROR: Chunk index must be less than chunks count" - exit 1 - fi - - set +e - # Ignore requirements as we don't have the libs. The requirements will be checked in the run_test function - ${COUNT_SKETCHES} "$test_folder" "$target" "1" - sketchcount=$? - set -e - sketches=$(cat sketches.txt) - rm -rf sketches.txt - - chunk_size=$(( $sketchcount / $chunk_max )) - all_chunks=$(( $chunk_max * $chunk_size )) - if [ "$all_chunks" -lt "$sketchcount" ]; then - chunk_size=$(( $chunk_size + 1 )) - fi - - start_index=0 - end_index=0 - if [ "$chunk_index" -ge "$chunk_max" ]; then - start_index=$chunk_index - end_index=$sketchcount - else - start_index=$(( $chunk_index * $chunk_size )) - if [ "$sketchcount" -le "$start_index" ]; then - exit 0 - fi - - end_index=$(( $(( $chunk_index + 1 )) * $chunk_size )) - if [ "$end_index" -gt "$sketchcount" ]; then - end_index=$sketchcount - fi - fi - - start_num=$(( $start_index + 1 )) - sketchnum=0 - error=0 - - for sketch in $sketches; do - - sketchnum=$(($sketchnum + 1)) - if [ "$sketchnum" -le "$start_index" ] \ - || [ "$sketchnum" -gt "$end_index" ]; then - continue - fi - - printf "\033[95mSketch Index $(($sketchnum - 1))\033[0m\n" - - exit_code=0 - run_test $target $sketch $options $erase || exit_code=$? - if [ $exit_code -ne 0 ]; then - error=$exit_code - fi - done - exit $error + if [ "$chunk_max" -le 0 ]; then + echo "ERROR: Chunks count must be positive number" + exit 1 + fi + + if [ "$chunk_index" -ge "$chunk_max" ] && [ "$chunk_max" -ge 2 ]; then + echo "ERROR: Chunk index must be less than chunks count" + exit 1 + fi + + set +e + # Ignore requirements as we don't have the libs. The requirements will be checked in the run_test function + ${COUNT_SKETCHES} "$test_folder" "$target" "1" + sketchcount=$? + set -e + sketches=$(cat sketches.txt) + rm -rf sketches.txt + + chunk_size=$(( sketchcount / chunk_max )) + all_chunks=$(( chunk_max * chunk_size )) + if [ "$all_chunks" -lt "$sketchcount" ]; then + chunk_size=$(( chunk_size + 1 )) + fi + + start_index=0 + end_index=0 + if [ "$chunk_index" -ge "$chunk_max" ]; then + start_index=$chunk_index + end_index=$sketchcount + else + start_index=$(( chunk_index * chunk_size )) + if [ "$sketchcount" -le "$start_index" ]; then + exit 0 + fi + + end_index=$(( $(( chunk_index + 1 )) * chunk_size )) + if [ "$end_index" -gt "$sketchcount" ]; then + end_index=$sketchcount + fi + fi + + sketchnum=0 + error=0 + + for sketch in $sketches; do + + sketchnum=$((sketchnum + 1)) + if [ "$sketchnum" -le "$start_index" ] \ + || [ "$sketchnum" -gt "$end_index" ]; then + continue + fi + + printf "\033[95mSketch Index %s\033[0m\n" "$((sketchnum - 1))" + + exit_code=0 + run_test "$target" "$sketch" $options $erase || exit_code=$? + if [ $exit_code -ne 0 ]; then + error=$exit_code + fi + done + exit $error fi diff --git a/.github/scripts/update-version.sh b/.github/scripts/update-version.sh index cbc31378b15..9a38b27a57a 100755 --- a/.github/scripts/update-version.sh +++ b/.github/scripts/update-version.sh @@ -1,20 +1,21 @@ #!/bin/bash +# shellcheck disable=SC2002 # For reference: add tools for all boards by replacing one line in each board # "[board].upload.tool=esptool_py" to "[board].upload.tool=esptool_py\n[board].upload.tool.default=esptool_py\n[board].upload.tool.network=esp_ota" #cat boards.txt | sed "s/\([a-zA-Z0-9_\-]*\)\.upload\.tool\=esptool_py/\1\.upload\.tool\=esptool_py\\n\1\.upload\.tool\.default\=esptool_py\\n\1\.upload\.tool\.network\=esp_ota/" if [ ! $# -eq 3 ]; then - echo "Bad number of arguments: $#" >&2 - echo "usage: $0 " >&2 - exit 1 + echo "Bad number of arguments: $#" >&2 + echo "usage: $0 " >&2 + exit 1 fi re='^[0-9]+$' if [[ ! $1 =~ $re ]] || [[ ! $2 =~ $re ]] || [[ ! $3 =~ $re ]] ; then - echo "error: Not a valid version: $1.$2.$3" >&2 - echo "usage: $0 " >&2 - exit 1 + echo "error: Not a valid version: $1.$2.$3" >&2 + echo "usage: $0 " >&2 + exit 1 fi ESP_ARDUINO_VERSION_MAJOR="$1" @@ -36,11 +37,12 @@ sed "s/#define ESP_ARDUINO_VERSION_MAJOR.*/#define ESP_ARDUINO_VERSION_MAJOR $ES sed "s/#define ESP_ARDUINO_VERSION_MINOR.*/#define ESP_ARDUINO_VERSION_MINOR $ESP_ARDUINO_VERSION_MINOR/g" | \ sed "s/#define ESP_ARDUINO_VERSION_PATCH.*/#define ESP_ARDUINO_VERSION_PATCH $ESP_ARDUINO_VERSION_PATCH/g" > __esp_arduino_version.h && mv __esp_arduino_version.h cores/esp32/esp_arduino_version.h -for lib in `ls libraries`; do - if [ -f "libraries/$lib/library.properties" ]; then - echo "Updating Library $lib..." - cat "libraries/$lib/library.properties" | sed "s/version=.*/version=$ESP_ARDUINO_VERSION/g" > "libraries/$lib/__library.properties" && mv "libraries/$lib/__library.properties" "libraries/$lib/library.properties" - fi +libraries=$(find libraries -maxdepth 1 -mindepth 1 -type d -exec basename {} \;) +for lib in $libraries; do + if [ -f "libraries/$lib/library.properties" ]; then + echo "Updating Library $lib..." + cat "libraries/$lib/library.properties" | sed "s/version=.*/version=$ESP_ARDUINO_VERSION/g" > "libraries/$lib/__library.properties" && mv "libraries/$lib/__library.properties" "libraries/$lib/library.properties" + fi done exit 0 diff --git a/.github/scripts/upload_py_tools.sh b/.github/scripts/upload_py_tools.sh index 0544bccd710..abe18a50c6e 100755 --- a/.github/scripts/upload_py_tools.sh +++ b/.github/scripts/upload_py_tools.sh @@ -1,11 +1,12 @@ #!/bin/bash + CHANGED_FILES=$1 echo "Pushing '$CHANGED_FILES' as github-actions[bot]" git config --global github.user "github-actions[bot]" git config --global user.name "github-actions[bot]" git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" for tool in $CHANGED_FILES; do - git add tools/$tool.exe + git add tools/"$tool".exe done git commit -m "change(tools): Push generated binaries to PR" git push diff --git a/.github/workflows/allboards.yml b/.github/workflows/allboards.yml index 4a2d4349ac3..8c4dadcd03e 100644 --- a/.github/workflows/allboards.yml +++ b/.github/workflows/allboards.yml @@ -1,6 +1,6 @@ name: Boards Test - Remote trigger -# The workflow will run on remote dispath with event-type set to "test-boards" +# The workflow will run on remote dispatch with event-type set to "test-boards" on: repository_dispatch: types: [test-boards] @@ -20,8 +20,7 @@ jobs: ref: ${{ github.event.client_payload.branch }} - name: Get boards fqbns - run: - bash .github/scripts/find_all_boards.sh + run: bash .github/scripts/find_all_boards.sh setup-chunks: needs: find-boards @@ -43,8 +42,7 @@ jobs: - id: set-test-chunks name: Set Chunks - run: - echo "test-chunks<> $GITHUB_OUTPUT + run: echo "test-chunks<> $GITHUB_OUTPUT echo "$( jq -nc '${{ needs.find-boards.outputs.fqbns }} | [_nwise( ${{ needs.find-boards.outputs.board-count }}/15 | ceil)]')" >> $GITHUB_OUTPUT @@ -61,7 +59,7 @@ jobs: strategy: fail-fast: false - matrix: + matrix: chunk: ${{ fromJSON(needs.setup-chunks.outputs['test-chunks']) }} steps: @@ -71,9 +69,8 @@ jobs: ref: ${{ github.event.client_payload.branch }} - name: Echo FQBNS to file - run: - echo "$FQBN" > fqbns.json - env: + run: echo "$FQBN" > fqbns.json + env: FQBN: ${{ toJSON(matrix.chunk) }} - name: Compile sketch @@ -88,5 +85,4 @@ jobs: enable-warnings-report: false cli-compile-flags: | - --warnings="all" - sketch-paths: - "- ./libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino" + sketch-paths: "- ./libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino" diff --git a/.github/workflows/boards.yml b/.github/workflows/boards.yml index a309e4ed2ce..a51c794cfb4 100644 --- a/.github/workflows/boards.yml +++ b/.github/workflows/boards.yml @@ -4,9 +4,9 @@ name: Boards Test on: pull_request: paths: - - 'boards.txt' - - 'libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino' - - '.github/workflows/boards.yml' + - "boards.txt" + - "libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino" + - ".github/workflows/boards.yml" env: # It's convenient to set variables for values used multiple times in the workflow @@ -28,8 +28,7 @@ jobs: uses: dcarbone/install-jq-action@v1.0.1 - name: Get board name - run: - bash .github/scripts/find_new_boards.sh ${{ github.repository }} ${{github.base_ref}} + run: bash .github/scripts/find_new_boards.sh ${{ github.repository }} ${{github.base_ref}} test-boards: needs: find-boards @@ -72,7 +71,7 @@ jobs: ./tools/openocd-esp32 ./tools/riscv32-* ./tools/xtensa-* - + - name: Compile sketch uses: P-R-O-C-H-Y/compile-sketches@main with: @@ -85,6 +84,5 @@ jobs: cli-compile-flags: | - --warnings="all" exit-on-fail: true - sketch-paths: - "- ./libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino" + sketch-paths: "- ./libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino" verbose: true diff --git a/.github/workflows/build_py_tools.yml b/.github/workflows/build_py_tools.yml index 37742d15224..48e7f2c82d3 100644 --- a/.github/workflows/build_py_tools.yml +++ b/.github/workflows/build_py_tools.yml @@ -3,11 +3,11 @@ name: Build Python Tools on: pull_request: paths: - - '.github/workflows/build_py_tools.yml' - - 'tools/get.py' - - 'tools/espota.py' - - 'tools/gen_esp32part.py' - - 'tools/gen_insights_package.py' + - ".github/workflows/build_py_tools.yml" + - "tools/get.py" + - "tools/espota.py" + - "tools/gen_esp32part.py" + - "tools/gen_insights_package.py" jobs: find-changed-tools: @@ -33,8 +33,8 @@ jobs: uses: tj-actions/changed-files@v41 id: verify-changed-files with: - fetch_depth: '2' - since_last_remote_commit: 'true' + fetch_depth: "2" + since_last_remote_commit: "true" files: | tools/get.py tools/espota.py @@ -57,20 +57,20 @@ jobs: matrix: os: [windows-latest, macos-latest, ubuntu-20.04, ARM] include: - - os: windows-latest - TARGET: win64 - EXTEN: .exe - SEPARATOR: ';' - - os: macos-latest - TARGET: macos - SEPARATOR: ':' - - os: ubuntu-20.04 - TARGET: linux-amd64 - SEPARATOR: ':' - - os: ARM - CONTAINER: python:3.8-bullseye - TARGET: arm - SEPARATOR: ':' + - os: windows-latest + TARGET: win64 + EXTEN: .exe + SEPARATOR: ";" + - os: macos-latest + TARGET: macos + SEPARATOR: ":" + - os: ubuntu-20.04 + TARGET: linux-amd64 + SEPARATOR: ":" + - os: ARM + CONTAINER: python:3.8-bullseye + TARGET: arm + SEPARATOR: ":" container: ${{ matrix.CONTAINER }} # use python container on ARM env: DISTPATH: pytools-${{ matrix.TARGET }} diff --git a/.github/workflows/dangerjs.yml b/.github/workflows/dangerjs.yml index 75c046731f3..f4bdad3c16e 100644 --- a/.github/workflows/dangerjs.yml +++ b/.github/workflows/dangerjs.yml @@ -11,14 +11,14 @@ jobs: pull-request-style-linter: runs-on: ubuntu-latest steps: - - name: Check out PR head - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} + - name: Check out PR head + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - - name: DangerJS pull request linter - uses: espressif/shared-github-dangerjs@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - rule-max-commits: 'false' - commit-messages-min-summary-length: '10' + - name: DangerJS pull request linter + uses: espressif/shared-github-dangerjs@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + rule-max-commits: "false" + commit-messages-min-summary-length: "10" diff --git a/.github/workflows/docs_build.yml b/.github/workflows/docs_build.yml index ffa5a0b4580..d2f12e1f7b5 100644 --- a/.github/workflows/docs_build.yml +++ b/.github/workflows/docs_build.yml @@ -3,18 +3,17 @@ name: Documentation Build and Deploy CI on: push: branches: - - master - - release/v2.x + - master + - release/v2.x paths: - - 'docs/**' - - '.github/workflows/docs_build.yml' + - "docs/**" + - ".github/workflows/docs_build.yml" pull_request: paths: - - 'docs/**' - - '.github/workflows/docs_build.yml' + - "docs/**" + - ".github/workflows/docs_build.yml" jobs: - build-docs: name: Build ESP-Docs runs-on: ubuntu-22.04 @@ -22,25 +21,25 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: actions/setup-python@v5 - with: - cache-dependency-path: docs/requirements.txt - cache: 'pip' - python-version: '3.10' - - name: Build - run: | - sudo apt update - sudo apt install python3-pip python3-setuptools - # GitHub CI installs pip3 and setuptools outside the path. - # Update the path to include them and run. - cd ./docs - PATH=/home/runner/.local/bin:$PATH pip3 install -r requirements.txt --prefer-binary - PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" build-docs -l en - - name: Archive Docs - uses: actions/upload-artifact@v4 - with: - name: docs - path: docs + - uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-python@v5 + with: + cache-dependency-path: docs/requirements.txt + cache: "pip" + python-version: "3.10" + - name: Build + run: | + sudo apt update + sudo apt install python3-pip python3-setuptools + # GitHub CI installs pip3 and setuptools outside the path. + # Update the path to include them and run. + cd ./docs + PATH=/home/runner/.local/bin:$PATH pip3 install -r requirements.txt --prefer-binary + PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" build-docs -l en + - name: Archive Docs + uses: actions/upload-artifact@v4 + with: + name: docs + path: docs diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml index 5393f7e8a20..b558fd21aa5 100644 --- a/.github/workflows/docs_deploy.yml +++ b/.github/workflows/docs_deploy.yml @@ -7,11 +7,11 @@ on: - completed push: branches: - - release/v2.x - - master + - release/v2.x + - master paths: - - 'docs/**' - - '.github/workflows/docs_deploy.yml' + - "docs/**" + - ".github/workflows/docs_deploy.yml" jobs: deploy-prod-docs: @@ -21,39 +21,39 @@ jobs: run: shell: bash steps: - - name: Check if release workflow is successful - if: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.conclusion != 'success' }} - run: | - echo "Release workflow failed. Exiting..." - exit 1 - - uses: actions/checkout@v4 - with: - submodules: true - - uses: actions/setup-python@v5 - with: - cache-dependency-path: docs/requirements.txt - cache: 'pip' - python-version: '3.10' - - name: Deploy Documentation - env: - # Deploy to production server - # DOCS_BUILD_DIR: "./docs/_build/" - DOCS_DEPLOY_PRIVATEKEY: ${{ secrets.DOCS_KEY }} - DOCS_DEPLOY_PATH: ${{ secrets.DOCS_PATH }} - DOCS_DEPLOY_SERVER: ${{ secrets.DOCS_SERVER }} - DOCS_DEPLOY_SERVER_USER: ${{ secrets.DOCS_USER }} - DOCS_DEPLOY_URL_BASE: ${{ secrets.DOCS_URL }} - run: | - sudo apt update - sudo apt install python3-pip python3-setuptools - source ./docs/utils.sh - add_doc_server_ssh_keys $DOCS_DEPLOY_PRIVATEKEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER - export GIT_VER=$(git describe --always) - echo "PIP install requirements..." - pip3 install --user -r ./docs/requirements.txt - echo "Building the Docs..." - cd ./docs && build-docs -l en - echo "Deploy the Docs..." - export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs/ - cd $GITHUB_WORKSPACE/docs - deploy-docs + - name: Check if release workflow is successful + if: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.conclusion != 'success' }} + run: | + echo "Release workflow failed. Exiting..." + exit 1 + - uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-python@v5 + with: + cache-dependency-path: docs/requirements.txt + cache: "pip" + python-version: "3.10" + - name: Deploy Documentation + env: + # Deploy to production server + # DOCS_BUILD_DIR: "./docs/_build/" + DOCS_DEPLOY_PRIVATEKEY: ${{ secrets.DOCS_KEY }} + DOCS_DEPLOY_PATH: ${{ secrets.DOCS_PATH }} + DOCS_DEPLOY_SERVER: ${{ secrets.DOCS_SERVER }} + DOCS_DEPLOY_SERVER_USER: ${{ secrets.DOCS_USER }} + DOCS_DEPLOY_URL_BASE: ${{ secrets.DOCS_URL }} + run: | + sudo apt update + sudo apt install python3-pip python3-setuptools + source ./docs/utils.sh + add_doc_server_ssh_keys $DOCS_DEPLOY_PRIVATEKEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER + export GIT_VER=$(git describe --always) + echo "PIP install requirements..." + pip3 install --user -r ./docs/requirements.txt + echo "Building the Docs..." + cd ./docs && build-docs -l en + echo "Deploy the Docs..." + export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs/ + cd $GITHUB_WORKSPACE/docs + deploy-docs diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 5d8e1794a8a..47480e8239a 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -3,21 +3,20 @@ name: GitHub Pages CI on: push: branches: - - master - - pages + - master + - pages paths: - - 'README.md' - - '.github/scripts/on-pages.sh' - - '.github/workflows/gh-pages.yml' + - "README.md" + - ".github/scripts/on-pages.sh" + - ".github/workflows/gh-pages.yml" jobs: - build-pages: name: Build GitHub Pages runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Copy Files - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bash ./.github/scripts/on-pages.sh + - uses: actions/checkout@v4 + - name: Copy Files + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: bash ./.github/scripts/on-pages.sh diff --git a/.github/workflows/lib.yml b/.github/workflows/lib.yml index 894df61f4fd..1197308c921 100644 --- a/.github/workflows/lib.yml +++ b/.github/workflows/lib.yml @@ -7,7 +7,7 @@ on: # Schedule weekly builds on every Sunday at 4 am schedule: - - cron: '0 4 * * SUN' + - cron: "0 4 * * SUN" concurrency: group: libs-${{ github.event.pull_request.number || github.ref }} @@ -27,7 +27,6 @@ jobs: contains(github.event.pull_request.labels.*.name, 'lib_test') || (github.event_name == 'schedule' && github.repository == 'espressif/arduino-esp32') runs-on: ubuntu-latest - env: REPOSITORY: | - source-path: '.' @@ -42,6 +41,7 @@ jobs: - esp32s3 - esp32c6 - esp32h2 + - esp32p4 include: - target: esp32 @@ -56,7 +56,8 @@ jobs: fqbn: espressif:esp32:esp32c6 - target: esp32h2 fqbn: espressif:esp32:esp32h2 - + - target: esp32p4 + fqbn: espressif:esp32:esp32p4 steps: # This step makes the contents of the repository available to the workflow @@ -85,7 +86,7 @@ jobs: path: ${{ env.SKETCHES_REPORTS_PATH }} report-to-file: - needs: compile-sketch # Wait for the compile job to finish to get the data for the report + needs: compile-sketch # Wait for the compile job to finish to get the data for the report if: github.event_name == 'schedule' # Only run the job when the workflow is triggered by a schedule runs-on: ubuntu-latest steps: @@ -94,11 +95,10 @@ jobs: uses: actions/checkout@v4 with: token: ${{ env.GITHUB_TOKEN }} - fetch-depth: '0' + fetch-depth: "0" - name: Switch branch - run: - git checkout remotes/origin/gh-pages + run: git checkout remotes/origin/gh-pages # This step is needed to get the size data produced by the compile jobs - name: Download sketches reports artifact @@ -115,8 +115,7 @@ jobs: destination-file: ${{ env.RESULT_LIBRARY_TEST_FILE }} - name: Append file with action URL - run: - echo "/ [GitHub Action Link](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})" >> ${{ env.RESULT_LIBRARY_TEST_FILE }} + run: echo "/ [GitHub Action Link](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})" >> ${{ env.RESULT_LIBRARY_TEST_FILE }} - name: Push to github repo run: | diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 8257e78c822..dc009e445da 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -37,7 +37,7 @@ jobs: uses: actions/setup-python@v5 with: cache-dependency-path: tools/pre-commit/requirements.txt - cache: 'pip' + cache: "pip" python-version: "3.x" - name: Get Python version hash diff --git a/.github/workflows/publishlib.yml b/.github/workflows/publishlib.yml index 7fd932f5309..62393b80915 100644 --- a/.github/workflows/publishlib.yml +++ b/.github/workflows/publishlib.yml @@ -47,7 +47,7 @@ jobs: uses: juliangruber/read-file-action@v1 with: path: ./artifacts/workflows/pr_num.txt - + - name: Report results uses: P-R-O-C-H-Y/report-size-deltas@libs with: diff --git a/.github/workflows/publishsizes-2.x.yml b/.github/workflows/publishsizes-2.x.yml index bdd2fc311e4..ffbd751838c 100644 --- a/.github/workflows/publishsizes-2.x.yml +++ b/.github/workflows/publishsizes-2.x.yml @@ -11,11 +11,11 @@ env: jobs: sizes-test-results: - name: Sizes Comparsion Results + name: Sizes Comparison Results runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch + uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch with: ref: gh-pages @@ -41,8 +41,7 @@ jobs: destination-file: ${{ env.RESULT_SIZES_TEST_FILE }} - name: Append file with action URL - run: - echo "/ [GitHub Action Link](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})" >> ${{ env.RESULT_SIZES_TEST_FILE }} + run: echo "/ [GitHub Action Link](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})" >> ${{ env.RESULT_SIZES_TEST_FILE }} - name: Push to github repo run: | diff --git a/.github/workflows/publishsizes.yml b/.github/workflows/publishsizes.yml index ce4e94cd5e5..6c6d75eccce 100644 --- a/.github/workflows/publishsizes.yml +++ b/.github/workflows/publishsizes.yml @@ -14,7 +14,7 @@ env: jobs: sizes-test-results: - name: Sizes Comparsion Results + name: Sizes Comparison Results runs-on: ubuntu-latest if: | github.event.workflow_run.event == 'pull_request' && @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch + uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch with: ref: gh-pages diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 82159e1b8a4..2ca9e52e48d 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -2,32 +2,48 @@ name: Compilation Tests on: workflow_dispatch: + inputs: + log_level: + description: "Log level" + default: "none" + type: "choice" + required: true + options: + - "none" + - "error" + - "warn" + - "info" + - "debug" + - "verbose" + schedule: + # Every Sunday at 2:00 UTC run a build with verbose log level + - cron: "0 2 * * SUN" push: branches: - - master - - release/* + - master + - release/* pull_request: paths: - - 'cores/**' - - 'libraries/**' - - '!libraries/**.md' - - '!libraries/**.txt' - - '!libraries/**.properties' - - '!libraries/**.py' - - 'package/**' - - 'tools/**.py' - - 'platform.txt' - - 'programmers.txt' - - '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_*' + - "cores/**" + - "libraries/**" + - "!libraries/**.md" + - "!libraries/**.txt" + - "!libraries/**.properties" + - "!libraries/**.py" + - "package/**" + - "tools/**.py" + - "platform.txt" + - "programmers.txt" + - "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/**/*" @@ -49,8 +65,8 @@ jobs: 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 + - uses: actions/checkout@v4 + - run: bash ./.github/scripts/check-cmakelists.sh gen-chunks: name: Generate chunks @@ -61,27 +77,24 @@ jobs: build_libraries: ${{ steps.set-chunks.outputs.build_libraries }} build_static_sketches: ${{ steps.set-chunks.outputs.build_static_sketches }} build_idf: ${{ steps.set-chunks.outputs.build_idf }} - build_platformio: ${{ steps.set-chunks.outputs.build_platformio }} chunk_count: ${{ steps.set-chunks.outputs.chunk_count }} chunks: ${{ steps.set-chunks.outputs.chunks }} steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 2 + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 2 - - name: Get changed files - id: changed-files - uses: tj-actions/changed-files@v44 - with: - files_yaml: | + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v44 + with: + files_yaml: | core: - '.github/**' - - '!.github/scripts/install-platformio-esp32.sh' - 'cores/**' - 'package/**' - 'tools/**' - - '!tools/platformio-build.py' - 'platform.txt' - 'programmers.txt' - "variants/esp32/**/*" @@ -110,36 +123,31 @@ jobs: - 'Kconfig.projbuild' - 'CMakeLists.txt' - "variants/esp32c2/**/*" - platformio: - - 'package.json' - - '.github/scripts/install-platformio-esp32.sh' - - 'tools/platformio-build.py' - - name: Set chunks - id: set-chunks - env: - LIB_FILES: ${{ steps.changed-files.outputs.libraries_all_changed_files }} - IS_PR: ${{ github.event_name == 'pull_request' }} - MAX_CHUNKS: ${{ env.MAX_CHUNKS }} - BUILD_PLATFORMIO: ${{ steps.changed-files.outputs.platformio_any_changed == 'true' }} - BUILD_IDF: ${{ steps.changed-files.outputs.idf_any_changed == 'true' }} - BUILD_LIBRARIES: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }} - BUILD_STATIC_SKETCHES: ${{ steps.changed-files.outputs.static_sketeches_any_changed == 'true' }} - FS_CHANGED: ${{ steps.changed-files.outputs.fs_any_changed == 'true' }} - NETWORKING_CHANGED: ${{ steps.changed-files.outputs.networking_any_changed == 'true' }} - CORE_CHANGED: ${{ steps.changed-files.outputs.core_any_changed == 'true' }} - LIB_CHANGED: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }} - run: | - bash ./.github/scripts/set_push_chunks.sh + - name: Set chunks + id: set-chunks + env: + LIB_FILES: ${{ steps.changed-files.outputs.libraries_all_changed_files }} + IS_PR: ${{ github.event_name == 'pull_request' }} + MAX_CHUNKS: ${{ env.MAX_CHUNKS }} + BUILD_IDF: ${{ steps.changed-files.outputs.idf_any_changed == 'true' }} + BUILD_LIBRARIES: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }} + BUILD_STATIC_SKETCHES: ${{ steps.changed-files.outputs.static_sketeches_any_changed == 'true' }} + FS_CHANGED: ${{ steps.changed-files.outputs.fs_any_changed == 'true' }} + NETWORKING_CHANGED: ${{ steps.changed-files.outputs.networking_any_changed == 'true' }} + CORE_CHANGED: ${{ steps.changed-files.outputs.core_any_changed == 'true' }} + LIB_CHANGED: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }} + run: | + bash ./.github/scripts/set_push_chunks.sh - - name: Upload sketches found - if: ${{ steps.set-chunks.outputs.build_all == 'false' && steps.set-chunks.outputs.build_libraries == 'true' }} - uses: actions/upload-artifact@v4 - with: - name: sketches_found - path: sketches_found.txt - overwrite: true - if-no-files-found: error + - name: Upload sketches found + if: ${{ steps.set-chunks.outputs.build_all == 'false' && steps.set-chunks.outputs.build_libraries == 'true' }} + uses: actions/upload-artifact@v4 + with: + name: sketches_found + path: sketches_found.txt + overwrite: true + if-no-files-found: error # Ubuntu build-arduino-linux: @@ -153,45 +161,55 @@ jobs: chunk: ${{ fromJson(needs.gen-chunks.outputs.chunks) }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.x' + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" - - name: Get libs cache - uses: actions/cache@v4 - with: - key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} - path: | - ./tools/dist - ./tools/esp32-arduino-libs - ./tools/esptool - ./tools/mk* - ./tools/openocd-esp32 - ./tools/riscv32-* - ./tools/xtensa-* + - name: Get libs cache + uses: actions/cache@v4 + with: + key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} + path: | + ./tools/dist + ./tools/esp32-arduino-libs + ./tools/esptool + ./tools/mk* + ./tools/openocd-esp32 + ./tools/riscv32-* + ./tools/xtensa-* - - name: Build all sketches - if: ${{ needs.gen-chunks.outputs.build_all == 'true' }} - run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ env.MAX_CHUNKS }} 1 + - name: Set Log Level + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "LOG_LEVEL=${{ github.event.inputs.log_level }}" >> $GITHUB_ENV + elif [ "${{ github.event_name }}" == "schedule" ]; then + echo "LOG_LEVEL=verbose" >> $GITHUB_ENV + else + echo "LOG_LEVEL=none" >> $GITHUB_ENV + fi - - name: Download sketches found - if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }} - uses: actions/download-artifact@v4 - with: - name: sketches_found + - name: Build all sketches + if: ${{ needs.gen-chunks.outputs.build_all == 'true' }} + run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ env.MAX_CHUNKS }} 1 ${{ env.LOG_LEVEL }} - - name: Build selected sketches - if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }} - run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ needs.gen-chunks.outputs.chunk_count }} 1 sketches_found.txt + - name: Download sketches found + if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }} + uses: actions/download-artifact@v4 + with: + name: sketches_found - #Upload cli compile json as artifact - - name: Upload cli compile json - uses: actions/upload-artifact@v4 - with: - name: pr_cli_compile_${{ matrix.chunk }} - path: cli_compile_${{ matrix.chunk }}.json - overwrite: true + - name: Build selected sketches + if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }} + run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ needs.gen-chunks.outputs.chunk_count }} 1 ${{ env.LOG_LEVEL }} sketches_found.txt + + #Upload cli compile json as artifact + - name: Upload cli compile json + uses: actions/upload-artifact@v4 + with: + name: pr_cli_compile_${{ matrix.chunk }} + path: cli_compile_${{ matrix.chunk }}.json + overwrite: true # Windows and MacOS build-arduino-win-mac: @@ -205,34 +223,12 @@ jobs: os: [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 - - # 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 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Build Sketches + run: bash ./.github/scripts/on-push.sh build-esp-idf-component: name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }} @@ -249,8 +245,18 @@ 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_target: ["esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2"] + idf_ver: ["release-v5.3"] + 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 @@ -275,16 +281,15 @@ jobs: if: github.event_name == 'push' && github.ref == 'refs/heads/master' runs-on: ubuntu-latest steps: - # Check out repository + # Check out repository - name: Checkout repository uses: actions/checkout@v4 with: token: ${{secrets.GITHUB_TOKEN}} - fetch-depth: '0' + fetch-depth: "0" - name: Switch branch - run: - git checkout remotes/origin/gh-pages + run: git checkout remotes/origin/gh-pages - name: Download sketches reports artifact uses: actions/download-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f8aa779d994..53a512dd54f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,15 +10,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: actions/setup-python@v5 - with: - python-version: '3.x' - - run: pip install packaging - - run: pip install pyserial - - name: Build Release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bash ./.github/scripts/on-release.sh + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + - run: pip install packaging + - run: pip install pyserial + - name: Build Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: bash ./.github/scripts/on-release.sh diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f57a1925c1c..0db3b98782b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,22 +16,22 @@ on: pull_request: types: [opened, reopened, closed, synchronize, labeled, unlabeled] paths: - - '.github/workflows/tests*' - - '.github/scripts/*.sh' - - '!.github/scripts/check-cmakelists.sh' - - '!.github/scripts/find_*' - - '!.github/scripts/on-*.sh' - - '!.github/scripts/set_push_chunks.sh' - - '!.github/scripts/update-version.sh' - - '!.github/scripts/upload_py_tools.sh' - - 'tests/**' - - 'cores/**' - - 'libraries/*/src/**.cpp' - - 'libraries/*/src/**.h' - - 'libraries/*/src/**.c' - - 'package/**' + - ".github/workflows/tests*" + - ".github/scripts/*.sh" + - "!.github/scripts/check-cmakelists.sh" + - "!.github/scripts/find_*" + - "!.github/scripts/on-*.sh" + - "!.github/scripts/set_push_chunks.sh" + - "!.github/scripts/update-version.sh" + - "!.github/scripts/upload_py_tools.sh" + - "tests/**" + - "cores/**" + - "libraries/*/src/**.cpp" + - "libraries/*/src/**.h" + - "libraries/*/src/**.c" + - "package/**" schedule: - - cron: '0 2 * * *' + - cron: "0 2 * * *" concurrency: group: tests-${{ github.event.pull_request.number || github.ref }} @@ -115,7 +115,7 @@ jobs: fail-fast: false matrix: type: ${{ fromJson(needs.gen-matrix.outputs.qemu-types) }} - chip: ['esp32', 'esp32c3'] + chip: ["esp32", "esp32c3"] with: type: ${{ matrix.type }} chip: ${{ matrix.chip }} diff --git a/.github/workflows/tests_build.yml b/.github/workflows/tests_build.yml index 090dfa8136b..7a5a2959657 100644 --- a/.github/workflows/tests_build.yml +++ b/.github/workflows/tests_build.yml @@ -5,11 +5,11 @@ on: inputs: type: type: string - description: 'Type of tests to build' + description: "Type of tests to build" required: true chip: type: string - description: 'Chip to build tests for' + description: "Chip to build tests for" required: true jobs: diff --git a/.github/workflows/tests_hw.yml b/.github/workflows/tests_hw.yml index d7922500f10..76480ed7c0e 100644 --- a/.github/workflows/tests_hw.yml +++ b/.github/workflows/tests_hw.yml @@ -5,11 +5,11 @@ on: inputs: type: type: string - description: 'Type of tests to run' + description: "Type of tests to run" required: true chip: type: string - description: 'Chip to run tests for' + description: "Chip to run tests for" required: true env: diff --git a/.github/workflows/tests_qemu.yml b/.github/workflows/tests_qemu.yml index 0b4ec18e7ac..6675909c9df 100644 --- a/.github/workflows/tests_qemu.yml +++ b/.github/workflows/tests_qemu.yml @@ -64,8 +64,8 @@ jobs: if: ${{ steps.check-tests.outputs.enabled == 'true' }} with: cache-dependency-path: tests/requirements.txt - cache: 'pip' - python-version: '3.x' + cache: "pip" + python-version: "3.x" - name: Install Python dependencies if: ${{ steps.check-tests.outputs.enabled == 'true' }} diff --git a/.github/workflows/tests_results.yml b/.github/workflows/tests_results.yml index f9c572bf546..947de64ece5 100644 --- a/.github/workflows/tests_results.yml +++ b/.github/workflows/tests_results.yml @@ -18,11 +18,11 @@ jobs: github.event.workflow_run.conclusion == 'timed_out' runs-on: ubuntu-latest permissions: - actions: write - statuses: write - checks: write - pull-requests: write - contents: write + actions: write + statuses: write + checks: write + pull-requests: write + contents: write steps: - uses: actions/checkout@v4 with: @@ -139,22 +139,23 @@ jobs: core.info(`${name} is ${state}`); - name: Create output folder - if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} + if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled run: | rm -rf artifacts mkdir -p runtime-tests-results - name: Generate badge - if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} + if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled uses: jaywcjlove/generated-badges@v1.0.13 with: label: Runtime Tests - status: ${{ job.status }} + status: ${{ job.status == 'success' && 'passing' || 'failing' }} output: runtime-tests-results/badge.svg color: ${{ job.status == 'success' && 'green' || 'red' }} + style: flat - name: Push badge - if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} + if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled run: | git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" diff --git a/.github/workflows/tests_wokwi.yml b/.github/workflows/tests_wokwi.yml index a891ca89dfd..f5eb2efcad2 100644 --- a/.github/workflows/tests_wokwi.yml +++ b/.github/workflows/tests_wokwi.yml @@ -247,8 +247,8 @@ jobs: if: ${{ steps.check-tests.outputs.enabled == 'true' }} with: cache-dependency-path: tests/requirements.txt - cache: 'pip' - python-version: '3.x' + cache: "pip" + python-version: "3.x" - name: Install dependencies if: ${{ steps.check-tests.outputs.enabled == 'true' }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6a949631bd9..f80261422b0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,8 +12,9 @@ default_language_version: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: "v4.5.0" + rev: "v5.0.0" hooks: + # Generic checks - id: check-case-conflict - id: check-symlinks - id: debug-statements @@ -25,6 +26,8 @@ repos: args: [--fix=lf] - id: trailing-whitespace args: [--markdown-linebreak-ext=md] + + # JSON formatting - id: pretty-format-json stages: [manual] args: [--autofix] @@ -35,40 +38,67 @@ repos: package\.json$| ^package\/.*$ ) + - repo: https://github.com/codespell-project/codespell rev: "v2.3.0" hooks: + # Spell checking - id: codespell exclude: ^.*\.(svd|SVD)$ + - repo: https://github.com/pre-commit/mirrors-clang-format rev: "v18.1.3" hooks: + # C/C++ formatting - id: clang-format types_or: [c, c++] exclude: ^.*\/build_opt\.h$ + - repo: https://github.com/psf/black-pre-commit-mirror - rev: "22.10.0" + rev: "24.10.0" hooks: + # Python formatting - id: black types_or: [python] args: [--line-length=120] #From the arduino code style. Add as argument rather than creating a new config file. + - repo: https://github.com/PyCQA/flake8 - rev: "7.0.0" + rev: "7.1.1" hooks: + # Python linting - id: flake8 types_or: [python] additional_dependencies: - flake8-bugbear - flake8-comprehensions - flake8-simplify + - repo: https://github.com/pre-commit/mirrors-prettier rev: "v3.1.0" hooks: + # YAML formatting - id: prettier types_or: [yaml] + + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: "v0.10.0.1" + hooks: + # Bash linting + - id: shellcheck + types: [shell] + + - repo: https://github.com/openstack/bashate + rev: "2.1.1" + hooks: + # Bash formatting + - id: bashate + types: [shell] + args: ["-i", "E006"] # Ignore E006: Line too long + - repo: https://github.com/errata-ai/vale - rev: "v3.0.7" + rev: "v3.9.1" hooks: + # Sync vale styles and lint markdown and reStructuredText - id: vale name: vale-sync language_version: "1.21.6" diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 00000000000..a7612e611a2 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,11 @@ +# Shellcheck configuration file for ESP32 Arduino core + +# Optional checks. https://github.com/koalaman/shellcheck/wiki/optional +enable=add-default-case,deprecate-which,avoid-nullary-conditions + +# Enable search for external sources +external-sources=true + +# Search folder for sourced files. +# Set to the folder where the original script is located. +source-path=SCRIPTDIR diff --git a/CMakeLists.txt b/CMakeLists.txt index a774deafd23..dd15e06dac8 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}") @@ -25,6 +25,7 @@ endif() set(CORE_SRCS cores/esp32/base64.cpp cores/esp32/cbuf.cpp + cores/esp32/ColorFormat.c cores/esp32/chip-debug-report.cpp cores/esp32/esp32-hal-adc.c cores/esp32/esp32-hal-bt.c @@ -45,9 +46,11 @@ 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 + cores/esp32/freertos_stats.cpp cores/esp32/FunctionalInterrupt.cpp cores/esp32/HardwareSerial.cpp cores/esp32/HEXBuilder.cpp @@ -93,6 +96,7 @@ set(ARDUINO_ALL_LIBRARIES HTTPUpdate Insights LittleFS + Matter NetBIOS Network OpenThread @@ -116,7 +120,6 @@ set(ARDUINO_ALL_LIBRARIES ) set(ARDUINO_LIBRARY_ArduinoOTA_SRCS libraries/ArduinoOTA/src/ArduinoOTA.cpp) -set(ARDUINO_LIBRARY_ArduinoOTA_REQUIRES esp_https_ota) set(ARDUINO_LIBRARY_AsyncUDP_SRCS libraries/AsyncUDP/src/AsyncUDP.cpp) @@ -157,7 +160,6 @@ 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 joltwallet__littlefs) set(ARDUINO_LIBRARY_NetBIOS_SRCS libraries/NetBIOS/src/NetBIOS.cpp) @@ -165,6 +167,22 @@ set(ARDUINO_LIBRARY_OpenThread_SRCS libraries/OpenThread/src/OThreadCLI.cpp libraries/OpenThread/src/OThreadCLI_Util.cpp) +set(ARDUINO_LIBRARY_Matter_SRCS + libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp + libraries/Matter/src/MatterEndpoints/MatterOnOffLight.cpp + libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp + libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp + libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp + libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.cpp + libraries/Matter/src/MatterEndpoints/MatterFan.cpp + libraries/Matter/src/MatterEndpoints/MatterTemperatureSensor.cpp + libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.cpp + libraries/Matter/src/MatterEndpoints/MatterContactSensor.cpp + libraries/Matter/src/MatterEndpoints/MatterPressureSensor.cpp + libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp + libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.cpp + libraries/Matter/src/Matter.cpp) + set(ARDUINO_LIBRARY_PPP_SRCS libraries/PPP/src/PPP.cpp libraries/PPP/src/ppp.c) @@ -258,10 +276,15 @@ set(ARDUINO_LIBRARY_Zigbee_SRCS libraries/Zigbee/src/ZigbeeHandlers.cpp libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp + libraries/Zigbee/src/ep/ZigbeeDimmableLight.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 + libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp + libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp + libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp + libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp ) set(ARDUINO_LIBRARY_BLE_SRCS @@ -317,7 +340,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) 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) @@ -328,6 +351,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}") @@ -367,9 +394,21 @@ 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) 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() +if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_LittleFS) + maybe_add_component(joltwallet__littlefs) +endif() +if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_WiFiProv) + maybe_add_component(espressif__network_provisioning) +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 diff --git a/README.md b/README.md index ee1880b8d05..e610229fc60 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ -# 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) +[![Build Status](https://img.shields.io/github/actions/workflow/status/espressif/arduino-esp32/push.yml?branch=master&event=push&label=Compilation%20Tests)](https://github.com/espressif/arduino-esp32/actions/workflows/push.yml?query=branch%3Amaster+event%3Apush) +[![Verbose Build Status](https://img.shields.io/github/actions/workflow/status/espressif/arduino-esp32/push.yml?branch=master&event=schedule&label=Compilation%20Tests%20(Verbose))](https://github.com/espressif/arduino-esp32/actions/workflows/push.yml?query=branch%3Amaster+event%3Aschedule) +[![External Libraries Test](https://img.shields.io/github/actions/workflow/status/espressif/arduino-esp32/lib.yml?branch=master&event=schedule&label=External%20Libraries%20Test)](https://github.com/espressif/arduino-esp32/blob/gh-pages/LIBRARIES_TEST.md) +[![Runtime 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) ### Need help or have a question? Join the chat at [Gitter](https://gitter.im/espressif/arduino-esp32) or [open a new Discussion](https://github.com/espressif/arduino-esp32/discussions) @@ -16,9 +19,17 @@ ### Development Status -Latest Stable Release [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Release Date](https://img.shields.io/github/release-date/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Downloads](https://img.shields.io/github/downloads/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) +#### Latest Stable Release -Latest Development Release [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Release Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Downloads](https://img.shields.io/github/downloads-pre/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) +[![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg)](https://github.com/espressif/arduino-esp32/releases/latest/) +[![Release Date](https://img.shields.io/github/release-date/espressif/arduino-esp32.svg)](https://github.com/espressif/arduino-esp32/releases/latest/) +[![Downloads](https://img.shields.io/github/downloads/espressif/arduino-esp32/latest/total.svg)](https://github.com/espressif/arduino-esp32/releases/latest/) + +#### Latest Development Release + +[![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg)](https://github.com/espressif/arduino-esp32/releases/) +[![Release Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg)](https://github.com/espressif/arduino-esp32/releases/) +[![Downloads](https://img.shields.io/github/downloads-pre/espressif/arduino-esp32/latest/total.svg)](https://github.com/espressif/arduino-esp32/releases/) ### Development Planning @@ -59,6 +70,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 | Yes | 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 diff --git a/boards.txt b/boards.txt index a740bde11d8..26ec251ecfe 100644 --- a/boards.txt +++ b/boards.txt @@ -161,6 +161,195 @@ esp32c2.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## +esp32p4.name=ESP32P4 Dev Module + +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=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 +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.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.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.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 +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) +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 +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 @@ -342,7 +531,15 @@ esp32h2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_co esp32h2.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) esp32h2.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP esp32h2.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port - +esp32h2.menu.ZigbeeMode.ed_debug=Zigbee ED (end device) - Debug +esp32h2.menu.ZigbeeMode.ed_debug.build.zigbee_mode=-DZIGBEE_MODE_ED +esp32h2.menu.ZigbeeMode.ed_debug.build.zigbee_libs=-lesp_zb_api_ed.debug -lesp_zb_cli_command -lzboss_stack.ed.debug -lzboss_port.debug +esp32h2.menu.ZigbeeMode.zczr_debug=Zigbee ZCZR (coordinator/router) - Debug +esp32h2.menu.ZigbeeMode.zczr_debug.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +esp32h2.menu.ZigbeeMode.zczr_debug.build.zigbee_libs=-lesp_zb_api_zczr.debug -lesp_zb_cli_command -lzboss_stack.zczr.debug -lzboss_port.debug +esp32h2.menu.ZigbeeMode.rcp_debug=Zigbee RCP (radio co-processor) - Debug +esp32h2.menu.ZigbeeMode.rcp_debug.build.zigbee_mode=-DZIGBEE_MODE_RCP +esp32h2.menu.ZigbeeMode.rcp_debug.build.zigbee_libs=-lesp_zb_api_rcp.debug -lesp_zb_cli_command -lzboss_stack.rcp.debug -lzboss_port.debug ############################################################## @@ -534,6 +731,15 @@ esp32c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_co esp32c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor) esp32c6.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP esp32c6.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port +esp32c6.menu.ZigbeeMode.ed_debug=Zigbee ED (end device) - Debug +esp32c6.menu.ZigbeeMode.ed_debug.build.zigbee_mode=-DZIGBEE_MODE_ED +esp32c6.menu.ZigbeeMode.ed_debug.build.zigbee_libs=-lesp_zb_api_ed.debug -lesp_zb_cli_command -lzboss_stack.ed.debug -lzboss_port.debug +esp32c6.menu.ZigbeeMode.zczr_debug=Zigbee ZCZR (coordinator/router) - Debug +esp32c6.menu.ZigbeeMode.zczr_debug.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +esp32c6.menu.ZigbeeMode.zczr_debug.build.zigbee_libs=-lesp_zb_api_zczr.debug -lesp_zb_cli_command -lzboss_stack.zczr.debug -lzboss_port.debug +esp32c6.menu.ZigbeeMode.rcp_debug=Zigbee RCP (radio co-processor) - Debug +esp32c6.menu.ZigbeeMode.rcp_debug.build.zigbee_mode=-DZIGBEE_MODE_RCP +esp32c6.menu.ZigbeeMode.rcp_debug.build.zigbee_libs=-lesp_zb_api_rcp.debug -lesp_zb_cli_command -lzboss_stack.rcp.debug -lzboss_port.debug ############################################################## 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/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/ColorFormat.c b/cores/esp32/ColorFormat.c new file mode 100644 index 00000000000..a01123545b3 --- /dev/null +++ b/cores/esp32/ColorFormat.c @@ -0,0 +1,279 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * 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 "ColorFormat.h" + +#include + +// define a clamp macro to substitute the std::clamp macro which is available from C++17 onwards +#define clamp(a, min, max) ((a) < (min) ? (min) : ((a) > (max) ? (max) : (a))) + +const espHsvColor_t HSV_BLACK = {0, 0, 0}; +const espHsvColor_t HSV_WHITE = {0, 0, 254}; +const espHsvColor_t HSV_RED = {0, 254, 254}; +const espHsvColor_t HSV_YELLOW = {42, 254, 254}; +const espHsvColor_t HSV_GREEN = {84, 254, 254}; +const espHsvColor_t HSV_CYAN = {127, 254, 254}; +const espHsvColor_t HSV_BLUE = {169, 254, 254}; +const espHsvColor_t HSV_MAGENTA = {211, 254, 254}; + +const espRgbColor_t RGB_BLACK = {0, 0, 0}; +const espRgbColor_t RGB_WHITE = {255, 255, 255}; +const espRgbColor_t RGB_RED = {255, 0, 0}; +const espRgbColor_t RGB_YELLOW = {255, 255, 0}; +const espRgbColor_t RGB_GREEN = {0, 255, 0}; +const espRgbColor_t RGB_CYAN = {0, 255, 255}; +const espRgbColor_t RGB_BLUE = {0, 0, 255}; +const espRgbColor_t RGB_MAGENTA = {255, 0, 255}; + +// main color temperature values +const espCtColor_t COOL_WHITE_COLOR_TEMPERATURE = {142}; +const espCtColor_t DAYLIGHT_WHITE_COLOR_TEMPERATURE = {181}; +const espCtColor_t WHITE_COLOR_TEMPERATURE = {250}; +const espCtColor_t SOFT_WHITE_COLOR_TEMPERATURE = {370}; +const espCtColor_t WARM_WHITE_COLOR_TEMPERATURE = {454}; + +espRgbColor_t espHsvToRgbColor(uint16_t h, uint8_t s, uint8_t v) { + espHsvColor_t hsv = {h, s, v}; + return espHsvColorToRgbColor(hsv); +} + +espRgbColor_t espHsvColorToRgbColor(espHsvColor_t hsv) { + espRgbColor_t rgb; + + uint8_t region, p, q, t; + uint32_t h, s, v, remainder; + + if (hsv.s == 0) { + rgb.r = rgb.g = rgb.b = hsv.v; + } else { + h = hsv.h; + s = hsv.s; + v = hsv.v; + + region = h / 43; + remainder = (h - (region * 43)) * 6; + p = (v * (255 - s)) >> 8; + q = (v * (255 - ((s * remainder) >> 8))) >> 8; + t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; + switch (region) { + case 0: rgb.r = v, rgb.g = t, rgb.b = p; break; + case 1: rgb.r = q, rgb.g = v, rgb.b = p; break; + case 2: rgb.r = p, rgb.g = v, rgb.b = t; break; + case 3: rgb.r = p, rgb.g = q, rgb.b = v; break; + case 4: rgb.r = t, rgb.g = p, rgb.b = v; break; + case 5: + default: rgb.r = v, rgb.g = p, rgb.b = q; break; + } + } + return rgb; +} + +espHsvColor_t espRgbToHsvColor(uint8_t r, uint8_t g, uint8_t b) { + espRgbColor_t rgb = {r, g, b}; + return espRgbColorToHsvColor(rgb); +} + +espHsvColor_t espRgbColorToHsvColor(espRgbColor_t rgb) { + espHsvColor_t hsv; + uint8_t rgbMin, rgbMax; + + rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b); + rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b); + + hsv.v = rgbMax; + if (hsv.v == 0) { + hsv.h = 0; + hsv.s = 0; + return hsv; + } + + hsv.s = 255 * (rgbMax - rgbMin) / hsv.v; + if (hsv.s == 0) { + hsv.h = 0; + return hsv; + } + if (rgbMax == rgb.r) { + hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin); + } else if (rgbMax == rgb.g) { + hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin); + } else { + hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin); + } + return hsv; +} + +espRgbColor_t espXYColorToRgbColor(uint8_t Level, espXyColor_t xy) { + return espXYToRgbColor(Level, xy.x, xy.y); +} + +espRgbColor_t espXYToRgbColor(uint8_t Level, uint16_t current_X, uint16_t current_Y) { + // convert xyY color space to RGB + + // https://www.easyrgb.com/en/math.php + // https://en.wikipedia.org/wiki/SRGB + // refer https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space + + // The current_X/current_Y attribute contains the current value of the normalized chromaticity value of x/y. + // The value of x/y shall be related to the current_X/current_Y attribute by the relationship + // x = current_X/65536 + // y = current_Y/65536 + // z = 1-x-y + + espRgbColor_t rgb; + + float x, y, z; + float X, Y, Z; + float r, g, b; + + x = ((float)current_X) / 65535.0f; + y = ((float)current_Y) / 65535.0f; + + z = 1.0f - x - y; + + // Calculate XYZ values + + // Y - given brightness in 0 - 1 range + Y = ((float)Level) / 254.0f; + X = (Y / y) * x; + Z = (Y / y) * z; + + // X, Y and Z input refer to a D65/2° standard illuminant. + // sR, sG and sB (standard RGB) output range = 0 ÷ 255 + // convert XYZ to RGB - CIE XYZ to sRGB + X = X / 100.0f; + Y = Y / 100.0f; + Z = Z / 100.0f; + + r = (X * 3.2406f) - (Y * 1.5372f) - (Z * 0.4986f); + g = -(X * 0.9689f) + (Y * 1.8758f) + (Z * 0.0415f); + b = (X * 0.0557f) - (Y * 0.2040f) + (Z * 1.0570f); + + // apply gamma 2.2 correction + r = (r <= 0.0031308f ? 12.92f * r : (1.055f) * pow(r, (1.0f / 2.4f)) - 0.055f); + g = (g <= 0.0031308f ? 12.92f * g : (1.055f) * pow(g, (1.0f / 2.4f)) - 0.055f); + b = (b <= 0.0031308f ? 12.92f * b : (1.055f) * pow(b, (1.0f / 2.4f)) - 0.055f); + + // Round off + r = clamp(r, 0, 1); + g = clamp(g, 0, 1); + b = clamp(b, 0, 1); + + // these rgb values are in the range of 0 to 1, convert to limit of HW specific LED + rgb.r = (uint8_t)(r * 255); + rgb.g = (uint8_t)(g * 255); + rgb.b = (uint8_t)(b * 255); + + return rgb; +} + +espXyColor_t espRgbToXYColor(uint8_t r, uint8_t g, uint8_t b) { + espRgbColor_t rgb = {r, g, b}; + return espRgbColorToXYColor(rgb); +} + +espXyColor_t espRgbColorToXYColor(espRgbColor_t rgb) { + // convert RGB to xy color space + + // https://www.easyrgb.com/en/math.php + // https://en.wikipedia.org/wiki/SRGB + // refer https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space + + espXyColor_t xy; + + float r, g, b; + float X, Y, Z; + float x, y; + + r = ((float)rgb.r) / 255.0f; + g = ((float)rgb.g) / 255.0f; + b = ((float)rgb.b) / 255.0f; + + // convert RGB to XYZ - sRGB to CIE XYZ + r = (r <= 0.04045f ? r / 12.92f : pow((r + 0.055f) / 1.055f, 2.4f)); + g = (g <= 0.04045f ? g / 12.92f : pow((g + 0.055f) / 1.055f, 2.4f)); + b = (b <= 0.04045f ? b / 12.92f : pow((b + 0.055f) / 1.055f, 2.4f)); + + // https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d + X = r * 0.649926f + g * 0.103455f + b * 0.197109f; + Y = r * 0.234327f + g * 0.743075f + b * 0.022598f; + Z = r * 0.0000000f + g * 0.053077f + b * 1.035763f; + + // sR, sG and sB (standard RGB) input range = 0 ÷ 255 + // X, Y and Z output refer to a D65/2° standard illuminant. + X = r * 0.4124564f + g * 0.3575761f + b * 0.1804375f; + Y = r * 0.2126729f + g * 0.7151522f + b * 0.0721750f; + Z = r * 0.0193339f + g * 0.1191920f + b * 0.9503041f; + + // Calculate xy values + x = X / (X + Y + Z); + y = Y / (X + Y + Z); + + // convert to 0-65535 range + xy.x = (uint16_t)(x * 65535); + xy.y = (uint16_t)(y * 65535); + return xy; +} + +espRgbColor_t espCTToRgbColor(uint16_t ct) { + espCtColor_t ctColor = {ct}; + return espCTColorToRgbColor(ctColor); +} + +espRgbColor_t espCTColorToRgbColor(espCtColor_t ct) { + espRgbColor_t rgb = {0, 0, 0}; + float r, g, b; + + if (ct.ctMireds == 0) { + return rgb; + } + // Algorithm credits to Tanner Helland: https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html + + // Convert Mireds to centiKelvins. k = 1,000,000/mired + float ctCentiKelvin = 10000 / ct.ctMireds; + + // Red + if (ctCentiKelvin <= 66) { + r = 255; + } else { + r = 329.698727446f * pow(ctCentiKelvin - 60, -0.1332047592f); + } + + // Green + if (ctCentiKelvin <= 66) { + g = 99.4708025861f * log(ctCentiKelvin) - 161.1195681661f; + } else { + g = 288.1221695283f * pow(ctCentiKelvin - 60, -0.0755148492f); + } + + // Blue + if (ctCentiKelvin >= 66) { + b = 255; + } else { + if (ctCentiKelvin <= 19) { + b = 0; + } else { + b = 138.5177312231 * log(ctCentiKelvin - 10) - 305.0447927307; + } + } + rgb.r = (uint8_t)clamp(r, 0, 255); + rgb.g = (uint8_t)clamp(g, 0, 255); + rgb.b = (uint8_t)clamp(b, 0, 255); + + return rgb; +} diff --git a/cores/esp32/ColorFormat.h b/cores/esp32/ColorFormat.h new file mode 100644 index 00000000000..0bb87145d16 --- /dev/null +++ b/cores/esp32/ColorFormat.h @@ -0,0 +1,70 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * 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 + +#include +#ifdef __cplusplus +extern "C" { +#endif + +struct RgbColor_t { + uint8_t r; + uint8_t g; + uint8_t b; +}; + +struct HsvColor_t { + uint16_t h; + uint8_t s; + uint8_t v; +}; + +struct XyColor_t { + uint16_t x; + uint16_t y; +}; + +struct CtColor_t { + uint16_t ctMireds; +}; + +typedef struct RgbColor_t espRgbColor_t; +typedef struct HsvColor_t espHsvColor_t; +typedef struct XyColor_t espXyColor_t; +typedef struct CtColor_t espCtColor_t; + +espRgbColor_t espXYToRgbColor(uint8_t Level, uint16_t current_X, uint16_t current_Y); +espRgbColor_t espXYColorToRgb(uint8_t Level, espXyColor_t xy); +espXyColor_t espRgbColorToXYColor(espRgbColor_t rgb); +espXyColor_t espRgbToXYColor(uint8_t r, uint8_t g, uint8_t b); +espRgbColor_t espHsvColorToRgbColor(espHsvColor_t hsv); +espRgbColor_t espHsvToRgbColor(uint16_t h, uint8_t s, uint8_t v); +espRgbColor_t espCTColorToRgbColor(espCtColor_t ct); +espRgbColor_t espCTToRgbColor(uint16_t ct); +espHsvColor_t espRgbColorToHsvColor(espRgbColor_t rgb); +espHsvColor_t espRgbToHsvColor(uint8_t r, uint8_t g, uint8_t b); + +extern const espHsvColor_t HSV_BLACK, HSV_WHITE, HSV_RED, HSV_YELLOW, HSV_GREEN, HSV_CYAN, HSV_BLUE, HSV_MAGENTA; +extern const espCtColor_t COOL_WHITE_COLOR_TEMPERATURE, DAYLIGHT_WHITE_COLOR_TEMPERATURE, WHITE_COLOR_TEMPERATURE, SOFT_WHITE_COLOR_TEMPERATURE, + WARM_WHITE_COLOR_TEMPERATURE; +extern const espRgbColor_t RGB_BLACK, RGB_WHITE, RGB_RED, RGB_YELLOW, RGB_GREEN, RGB_CYAN, RGB_BLUE, RGB_MAGENTA; + +#ifdef __cplusplus +} +#endif diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index f4d7c221bce..9f90a828b25 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 @@ -297,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 @@ -335,6 +339,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 +367,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/HWCDC.cpp b/cores/esp32/HWCDC.cpp index 780e560dcf8..170e323a035 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 c82cbb43d3b..fb93dad1c47 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -25,23 +25,37 @@ void serialEvent(void) __attribute__((weak)); -#if SOC_UART_NUM > 1 +#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_NUM > 2 +#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 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 +#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 @@ -274,8 +298,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; } @@ -289,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 @@ -304,7 +333,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 @@ -313,18 +342,55 @@ 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 +#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 fb9ac9a952b..a33d5def34d 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,12 +143,14 @@ 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 // 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 @@ -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,13 +186,15 @@ 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_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 +210,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,12 +365,18 @@ 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 +#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/IPAddress.cpp b/cores/esp32/IPAddress.cpp index b4fc4c3f7e0..299a625ff27 100644 --- a/cores/esp32/IPAddress.cpp +++ b/cores/esp32/IPAddress.cpp @@ -22,6 +22,10 @@ #include "lwip/netif.h" #include "StreamString.h" +#ifndef CONFIG_LWIP_IPV6 +#define IP6_NO_ZONE 0 +#endif + IPAddress::IPAddress() : IPAddress(IPv4) {} IPAddress::IPAddress(IPType ip_type) { @@ -201,7 +205,13 @@ bool IPAddress::fromString6(const char *address) { colons++; acc = 0; } else if (c == '%') { - _zone = netif_name_to_index(address); + // netif_index_to_name crashes on latest esp-idf + // _zone = netif_name_to_index(address); + // in the interim, we parse the suffix as a zone number + while ((*address != '\0') && (!isdigit(*address))) { // skip all non-digit after '%' + address++; + } + _zone = atol(address) + 1; // increase by one by convention, so we can have zone '0' while (*address != '\0') { address++; } @@ -344,12 +354,25 @@ size_t IPAddress::printTo(Print &p, bool includeZone) const { n += p.print(':'); } } - // add a zone if zone-id is non-zero + // 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); + // } + // In the interim, we just output the index number if (_zone > 0 && includeZone) { n += p.print('%'); - char if_name[NETIF_NAMESIZE]; - netif_index_to_name(_zone, if_name); - n += p.print(if_name); + // look for the interface name + for (netif *intf = netif_list; intf != nullptr; intf = intf->next) { + if (_zone - 1 == intf->num) { + n += p.print(intf->name[0]); + n += p.print(intf->name[1]); + break; + } + } + n += p.print(_zone - 1); } return n; } @@ -368,6 +391,7 @@ IPAddress::IPAddress(const ip_addr_t *addr) { } void IPAddress::to_ip_addr_t(ip_addr_t *addr) const { +#if CONFIG_LWIP_IPV6 if (_type == IPv6) { addr->type = IPADDR_TYPE_V6; addr->u_addr.ip6.addr[0] = _address.dword[0]; @@ -381,9 +405,13 @@ void IPAddress::to_ip_addr_t(ip_addr_t *addr) const { addr->type = IPADDR_TYPE_V4; addr->u_addr.ip4.addr = _address.dword[IPADDRESS_V4_DWORD_INDEX]; } +#else + addr->addr = _address.dword[IPADDRESS_V4_DWORD_INDEX]; +#endif } IPAddress &IPAddress::from_ip_addr_t(const ip_addr_t *addr) { +#if CONFIG_LWIP_IPV6 if (addr->type == IPADDR_TYPE_V6) { _type = IPv6; _address.dword[0] = addr->u_addr.ip6.addr[0]; @@ -394,13 +422,21 @@ IPAddress &IPAddress::from_ip_addr_t(const ip_addr_t *addr) { _zone = addr->u_addr.ip6.zone; #endif /* LWIP_IPV6_SCOPES */ } else { +#endif _type = IPv4; memset(_address.bytes, 0, sizeof(_address.bytes)); +#if CONFIG_LWIP_IPV6 _address.dword[IPADDRESS_V4_DWORD_INDEX] = addr->u_addr.ip4.addr; +#else + _address.dword[IPADDRESS_V4_DWORD_INDEX] = addr->addr; +#endif +#if CONFIG_LWIP_IPV6 } +#endif return *this; } +#if CONFIG_LWIP_IPV6 esp_ip6_addr_type_t IPAddress::addr_type() const { if (_type != IPv6) { return ESP_IP6_ADDR_IS_UNKNOWN; @@ -409,6 +445,9 @@ esp_ip6_addr_type_t IPAddress::addr_type() const { to_ip_addr_t(&addr); return esp_netif_ip6_get_addr_type((esp_ip6_addr_t *)(&(addr.u_addr.ip6))); } +#endif +#if CONFIG_LWIP_IPV6 const IPAddress IN6ADDR_ANY(IPv6); +#endif const IPAddress INADDR_NONE(0, 0, 0, 0); diff --git a/cores/esp32/IPAddress.h b/cores/esp32/IPAddress.h index b88aeed3026..923f4dd5ca6 100644 --- a/cores/esp32/IPAddress.h +++ b/cores/esp32/IPAddress.h @@ -24,6 +24,7 @@ #include "WString.h" #include "lwip/ip_addr.h" #include "esp_netif_ip_addr.h" +#include "sdkconfig.h" #define IPADDRESS_V4_BYTES_INDEX 12 #define IPADDRESS_V4_DWORD_INDEX 3 @@ -115,7 +116,9 @@ class IPAddress : public Printable { IPAddress(const ip_addr_t *addr); void to_ip_addr_t(ip_addr_t *addr) const; IPAddress &from_ip_addr_t(const ip_addr_t *addr); +#if CONFIG_LWIP_IPV6 esp_ip6_addr_type_t addr_type() const; +#endif uint8_t zone() const { return (type() == IPv6) ? _zone : 0; } 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/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 7027c7cad9d..1ffde860792 100644 --- a/cores/esp32/esp32-hal-cpu.c +++ b/cores/esp32/esp32-hal-cpu.c @@ -19,9 +19,9 @@ #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/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" @@ -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 @@ -260,16 +259,15 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) { if (apb_change_callbacks) { triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb); } -#ifdef SOC_CLK_APLL_SUPPORTED +#if defined(SOC_CLK_APLL_SUPPORTED) && !defined(CONFIG_IDF_TARGET_ESP32P4) // APLL not yet supported in ESP32-P4 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" : "8M")), 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 edae1e57c92..85eddcdfcf4 100644 --- a/cores/esp32/esp32-hal-i2c-slave.c +++ b/cores/esp32/esp32-hal-i2c-slave.c @@ -41,21 +41,40 @@ #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 -#if SOC_I2C_NUM > 1 +#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)) #else #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 @@ -99,14 +118,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 , @@ -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 } @@ -210,7 +229,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 +243,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; } @@ -306,17 +325,18 @@ 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_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 } else { periph_ll_enable_clk_clear_rst(PERIPH_I2C1_MODULE); #endif } +#endif // !defined(CONFIG_IDF_TARGET_ESP32P4) 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,15 +357,23 @@ 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) { +#if !defined(CONFIG_IDF_TARGET_ESP32P4) ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); -#if SOC_I2C_NUM > 1 +#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 } @@ -375,7 +403,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 +426,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 +543,20 @@ 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_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_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_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_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-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 86140144613..0bce548bdd2 100644 --- a/cores/esp32/esp32-hal-misc.c +++ b/cores/esp32/esp32-hal-misc.c @@ -30,9 +30,9 @@ #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/apb_ctrl_reg.h" +#include "soc/syscon_reg.h" #endif #include "esp_task_wdt.h" #include "esp32-hal.h" @@ -54,6 +54,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 @@ -148,14 +150,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"); } @@ -163,14 +165,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"); } @@ -251,7 +253,7 @@ extern bool btInUse(); #endif #if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM -ESP_SYSTEM_INIT_FN(init_psram_new, BIT(0), 99) { +ESP_SYSTEM_INIT_FN(init_psram_new, CORE, BIT(0), 99) { psramInit(); return ESP_OK; } diff --git a/cores/esp32/esp32-hal-psram.c b/cores/esp32/esp32-hal-psram.c index b1b13f53ef3..3c7a51c3343 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 @@ -79,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; 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/cores/esp32/esp32-hal-spi.c b/cores/esp32/esp32-hal-spi.c index 857c3d4bb2e..80928309670 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,12 +57,15 @@ #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 struct spi_struct_t { - spi_dev_t *dev; + volatile spi_dev_t *dev; #if !CONFIG_DISABLE_HAL_LOCKS SemaphoreHandle_t lock; #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,14 +148,15 @@ struct spi_struct_t { #if CONFIG_DISABLE_HAL_LOCKS #define SPI_MUTEX_LOCK() #define SPI_MUTEX_UNLOCK() - +// 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 - {(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_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} #elif CONFIG_IDF_TARGET_ESP32C3 @@ -146,6 +170,7 @@ static spi_t _spi_bus_array[] = { {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3, -1, -1, -1, -1} #endif }; +// clang-format on #else #define SPI_MUTEX_LOCK() \ do { \ @@ -157,7 +182,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 +394,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 +407,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 +440,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 +453,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 +481,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 +506,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 +580,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 +663,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 +685,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 +712,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 +733,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 +760,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 +791,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 +813,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 +854,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 +878,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 +913,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 +937,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 +987,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 +1004,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 +1076,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 +1116,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 +1145,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 +1164,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 +1194,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 +1216,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 +1249,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 +1271,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 +1313,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 +1352,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 +1360,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 +1376,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 +1394,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 +1436,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 +1488,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 +1539,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 +1584,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-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index f7225425913..f83e8b61bd2 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 { @@ -127,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, }; @@ -165,7 +173,16 @@ void deinit_usb_hal() { esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) { init_usb_hal(config->external_phy); - if (!tusb_init()) { + tusb_rhport_init_t tinit; + memset(&tinit, 0, sizeof(tusb_rhport_init_t)); + tinit.role = TUSB_ROLE_DEVICE; +#if CONFIG_IDF_TARGET_ESP32P4 + tinit.speed = TUSB_SPEED_HIGH; + if (!tusb_init(1, &tinit)) { +#else + tinit.speed = TUSB_SPEED_FULL; + if (!tusb_init(0, &tinit)) { +#endif log_e("Can't initialize the TinyUSB stack."); return ESP_FAIL; } @@ -275,15 +292,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) }; /* @@ -467,8 +483,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 +567,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 +599,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 +612,7 @@ void usb_persist_restart(restart_type_t mode) { #endif esp_restart(); } +#endif } static bool tinyusb_reserve_in_endpoint(uint8_t endpoint) { @@ -674,8 +696,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 +821,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,6 +834,7 @@ 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 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/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 d32b34d0173..701bf6d16c9 100644 --- a/cores/esp32/esp32-hal-touch.c +++ b/cores/esp32/esp32-hal-touch.c @@ -14,6 +14,8 @@ #include "soc/soc_caps.h" #if SOC_TOUCH_SENSOR_SUPPORTED +#if SOC_TOUCH_SENSOR_VERSION <= 2 // ESP32, ESP32S2, ESP32S3 + #include "driver/touch_sensor.h" #include "esp32-hal-touch.h" #include "esp32-hal-periman.h" @@ -22,10 +24,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 +39,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 +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_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 +70,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 +95,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 +125,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 +145,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; @@ -165,7 +167,6 @@ static void __touchInit() { touch_pad_fsm_start(); // returns ESP_OK //ISR setup moved to __touchChannelInit #endif - initialized = true; return; err: @@ -179,11 +180,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 +239,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 +271,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 +279,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 +308,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); @@ -324,4 +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 <= 2 */ #endif /* SOC_TOUCH_SENSOR_SUPPORTED */ diff --git a/cores/esp32/esp32-hal-touch.h b/cores/esp32/esp32-hal-touch.h index db33ce3bc6a..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" { @@ -29,13 +30,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 +72,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 +84,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 @@ -97,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-uart.c b/cores/esp32/esp32-hal-uart.c index 9eb117988f6..34a2660e3a3 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -33,7 +33,8 @@ #include "hal/gpio_hal.h" #include "esp_rom_gpio.h" -static int s_uart_debug_nr = 0; // UART number for debug output +static int s_uart_debug_nr = 0; // UART number for debug output +#define REF_TICK_BAUDRATE_LIMIT 250000 // this is maximum UART badrate using REF_TICK as clock struct uart_struct_t { @@ -61,12 +62,18 @@ 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 +#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 @@ -81,12 +88,18 @@ 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 +#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 @@ -94,8 +107,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 +194,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 +321,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 +391,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 +413,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]; @@ -497,6 +510,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; @@ -508,7 +523,7 @@ uart_t *uartBegin( #if SOC_UART_SUPPORT_XTAL_CLK uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4 #elif SOC_UART_SUPPORT_REF_TICK - if (baudrate <= 250000) { + if (baudrate <= REF_TICK_BAUDRATE_LIMIT) { uart_config.source_clk = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps } else { uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency! @@ -604,8 +619,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 @@ -623,7 +638,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) @@ -790,6 +805,10 @@ void uartSetBaudRate(uart_t *uart, uint32_t baud_rate) { return; } UART_MUTEX_LOCK(); +#if !SOC_UART_SUPPORT_XTAL_CLK + soc_module_clk_t newClkSrc = baud_rate <= REF_TICK_BAUDRATE_LIMIT ? SOC_MOD_CLK_REF_TICK : SOC_MOD_CLK_APB; + uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc); +#endif if (uart_set_baudrate(uart->num, baud_rate) == ESP_OK) { uart->_baudrate = baud_rate; } else { @@ -819,28 +838,48 @@ 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); } #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; -#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 +#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; } @@ -850,7 +889,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 +900,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; @@ -896,7 +935,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 @@ -1103,19 +1142,35 @@ 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 +#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)) #else #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. */ 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/cores/esp32/esp32-hal.h b/cores/esp32/esp32-hal.h index 60350ae960b..d0bd4b8bc93 100644 --- a/cores/esp32/esp32-hal.h +++ b/cores/esp32/esp32-hal.h @@ -61,6 +61,19 @@ extern "C" { #define ARDUINO_EVENT_RUNNING_CORE CONFIG_ARDUINO_EVENT_RUNNING_CORE #endif +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +static const uint8_t BOOT_PIN = 0; +#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C61 +static const uint8_t BOOT_PIN = 9; +#elif CONFIG_IDF_TARGET_ESP32P4 +static const uint8_t BOOT_PIN = 35; +#elif CONFIG_IDF_TARGET_ESP32C5 +static const uint8_t BOOT_PIN = 28; +#else +#error BOOT_PIN not defined for this chip! +#endif +#define BOOT_PIN BOOT_PIN + //forward declaration from freertos/portmacro.h void vPortYield(void); void yield(void); @@ -74,6 +87,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/esp_arduino_version.h b/cores/esp32/esp_arduino_version.h index d541b534ab4..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 5 +#define ESP_ARDUINO_VERSION_PATCH 0 /** * Macro to convert ARDUINO version number into an integer 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 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/docs/en/contributing.rst b/docs/en/contributing.rst index bc3e2e89674..fb7843f1fb6 100644 --- a/docs/en/contributing.rst +++ b/docs/en/contributing.rst @@ -178,6 +178,7 @@ Currently, the default FQBNs are: * ``espressif:esp32:esp32c3`` * ``espressif:esp32:esp32c6`` * ``espressif:esp32:esp32h2`` +* ``espressif:esp32:esp32p4:USBMode=default`` 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. @@ -440,6 +441,16 @@ For checking the code style and other code quality checks, we use pre-commit hoo These hooks will be automatically run by the CI when a Pull Request is marked as ``Status: Pending Merge``. You can check which hooks are being run in the ``.pre-commit-config.yaml`` file. +Currently, we have hooks for the following tasks: + +* Formatters for C, C++, Python, Bash, JSON, Markdown and ReStructuredText files; +* Linters for Python, Bash and prose (spoken language); +* Checking for spelling errors in the code and documentation; +* Removing trailing whitespaces and tabs in the code; +* Checking for the presence of private keys and other sensitive information in the code; +* Fixing the line endings and end of files (EOF) in the code; +* And more. + You can read more about the pre-commit hooks in the `pre-commit documentation `_. If you want to run the pre-commit hooks locally, you first need to install the required dependencies by running: diff --git a/docs/en/lib_builder.rst b/docs/en/lib_builder.rst index a05fd45d584..478becc3350 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/docs/utils.sh b/docs/utils.sh index 84f37489975..3a860ac8a2c 100644 --- a/docs/utils.sh +++ b/docs/utils.sh @@ -1,18 +1,19 @@ +#!/bin/bash # Bash helper functions for adding SSH keys -function add_ssh_keys() { - local key_string="${1}" - mkdir -p ~/.ssh - chmod 700 ~/.ssh - echo -n "${key_string}" >~/.ssh/id_rsa_base64 - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 >~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa +function add_ssh_keys { + local key_string="${1}" + mkdir -p ~/.ssh + chmod 700 ~/.ssh + echo -n "${key_string}" >~/.ssh/id_rsa_base64 + base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 >~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa } -function add_doc_server_ssh_keys() { - local key_string="${1}" - local server_url="${2}" - local server_user="${3}" - add_ssh_keys "${key_string}" - echo -e "Host ${server_url}\n\tStrictHostKeyChecking no\n\tUser ${server_user}\n" >>~/.ssh/config +function add_doc_server_ssh_keys { + local key_string="${1}" + local server_url="${2}" + local server_user="${3}" + add_ssh_keys "${key_string}" + echo -e "Host ${server_url}\n\tStrictHostKeyChecking no\n\tUser ${server_user}\n" >>~/.ssh/config } diff --git a/idf_component.yml b/idf_component.yml index abacb442ef2..9c6bd159d42 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -9,6 +9,7 @@ targets: - esp32c3 - esp32c6 - esp32h2 + - esp32p4 tags: - arduino files: @@ -20,6 +21,7 @@ files: - "variants/esp32c3/**/*" - "variants/esp32c6/**/*" - "variants/esp32h2/**/*" + - "variants/esp32p4/**/*" exclude: - "docs/" - "docs/**/*" @@ -42,47 +44,72 @@ 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" require: public espressif/esp_modem: version: "^1.1.0" - espressif/network_provisioning: - version: "~1.0.0" espressif/esp-zboss-lib: - version: "^1.0.1" + version: "==1.6.0" + require: public rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/esp-zigbee-lib: - version: "^1.0.1" + version: "==1.6.0" + require: public rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/esp-dsp: 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 != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/rmaker_common: - version: "^1.4.6" + version: "1.4.6" rules: - - if: "target != esp32c2" + - if: "target not in [esp32c2, esp32p4]" espressif/esp_insights: - version: "^1.2.1" + version: "1.0.1" rules: - - if: "target != esp32c2" + - 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 != esp32c2" + - if: "target not in [esp32c2, esp32p4]" + # RainMaker End espressif/esp-sr: version: "^1.4.2" rules: - if: "target in [esp32s3]" + espressif/esp_hosted: + version: "^0.0.25" + 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/ArduinoOTA/library.properties b/libraries/ArduinoOTA/library.properties index d3d9d08494b..54ad6eafb21 100644 --- a/libraries/ArduinoOTA/library.properties +++ b/libraries/ArduinoOTA/library.properties @@ -1,5 +1,5 @@ name=ArduinoOTA -version=3.0.5 +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/ArduinoOTA/src/ArduinoOTA.cpp b/libraries/ArduinoOTA/src/ArduinoOTA.cpp index 9dcf93a1d23..0ab5466ab20 100644 --- a/libraries/ArduinoOTA/src/ArduinoOTA.cpp +++ b/libraries/ArduinoOTA/src/ArduinoOTA.cpp @@ -134,10 +134,12 @@ void ArduinoOTAClass::begin() { sprintf(tmp, "esp32-%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); _hostname = tmp; } +#ifdef CONFIG_MDNS_MAX_INTERFACES if (_mdnsEnabled) { MDNS.begin(_hostname.c_str()); MDNS.enableArduino(_port, (_password.length() > 0)); } +#endif _initialized = true; _state = OTA_IDLE; log_i("OTA server at: %s.local:%u", _hostname.c_str(), _port); @@ -372,9 +374,11 @@ void ArduinoOTAClass::_runUpdate() { void ArduinoOTAClass::end() { _initialized = false; _udp_ota.stop(); +#ifdef CONFIG_MDNS_MAX_INTERFACES if (_mdnsEnabled) { MDNS.end(); } +#endif _state = OTA_IDLE; log_i("OTA server stopped."); } diff --git a/libraries/AsyncUDP/library.properties b/libraries/AsyncUDP/library.properties index ba0cb838673..24457a39b90 100644 --- a/libraries/AsyncUDP/library.properties +++ b/libraries/AsyncUDP/library.properties @@ -1,5 +1,5 @@ name=ESP32 Async UDP -version=3.0.5 +version=3.1.0 author=Me-No-Dev maintainer=Me-No-Dev sentence=Async UDP Library for ESP32 diff --git a/libraries/AsyncUDP/src/AsyncUDP.cpp b/libraries/AsyncUDP/src/AsyncUDP.cpp index 5549276de44..48714bce5c5 100644 --- a/libraries/AsyncUDP/src/AsyncUDP.cpp +++ b/libraries/AsyncUDP/src/AsyncUDP.cpp @@ -328,25 +328,36 @@ AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr, pbuf_ref(_pb); //memcpy(&_remoteIp, raddr, sizeof(ip_addr_t)); +#if CONFIG_LWIP_IPV6 _remoteIp.type = raddr->type; _localIp.type = _remoteIp.type; +#endif eth_hdr *eth = NULL; udp_hdr *udphdr = (udp_hdr *)(_data - UDP_HLEN); _localPort = ntohs(udphdr->dest); _remotePort = ntohs(udphdr->src); +#if CONFIG_LWIP_IPV6 if (_remoteIp.type == IPADDR_TYPE_V4) { +#endif eth = (eth_hdr *)(_data - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR); struct ip_hdr *iphdr = (struct ip_hdr *)(_data - UDP_HLEN - IP_HLEN); +#if CONFIG_LWIP_IPV6 _localIp.u_addr.ip4.addr = iphdr->dest.addr; _remoteIp.u_addr.ip4.addr = iphdr->src.addr; +#else + _localIp.addr = iphdr->dest.addr; + _remoteIp.addr = iphdr->src.addr; +#endif +#if CONFIG_LWIP_IPV6 } else { eth = (eth_hdr *)(_data - UDP_HLEN - IP6_HLEN - SIZEOF_ETH_HDR); struct ip6_hdr *ip6hdr = (struct ip6_hdr *)(_data - UDP_HLEN - IP6_HLEN); memcpy(&_localIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16); memcpy(&_remoteIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->src.addr, 16); } +#endif memcpy(_remoteMac, eth->src.addr, 6); struct netif *netif = NULL; @@ -413,36 +424,48 @@ tcpip_adapter_if_t AsyncUDPPacket::interface() { } IPAddress AsyncUDPPacket::localIP() { +#if CONFIG_LWIP_IPV6 if (_localIp.type != IPADDR_TYPE_V4) { return IPAddress(); } return IPAddress(_localIp.u_addr.ip4.addr); +#else + return IPAddress(_localIp.addr); +#endif } +#if CONFIG_LWIP_IPV6 IPAddress AsyncUDPPacket::localIPv6() { if (_localIp.type != IPADDR_TYPE_V6) { return IPAddress(IPv6); } return IPAddress(IPv6, (const uint8_t *)_localIp.u_addr.ip6.addr, _localIp.u_addr.ip6.zone); } +#endif uint16_t AsyncUDPPacket::localPort() { return _localPort; } IPAddress AsyncUDPPacket::remoteIP() { +#if CONFIG_LWIP_IPV6 if (_remoteIp.type != IPADDR_TYPE_V4) { return IPAddress(); } return IPAddress(_remoteIp.u_addr.ip4.addr); +#else + return IPAddress(_remoteIp.addr); +#endif } +#if CONFIG_LWIP_IPV6 IPAddress AsyncUDPPacket::remoteIPv6() { if (_remoteIp.type != IPADDR_TYPE_V6) { return IPAddress(IPv6); } return IPAddress(IPv6, (const uint8_t *)_remoteIp.u_addr.ip6.addr, _remoteIp.u_addr.ip6.zone); } +#endif uint16_t AsyncUDPPacket::remotePort() { return _remotePort; @@ -453,14 +476,22 @@ void AsyncUDPPacket::remoteMac(uint8_t *mac) { } bool AsyncUDPPacket::isIPv6() { +#if CONFIG_LWIP_IPV6 return _localIp.type == IPADDR_TYPE_V6; +#else + return false; +#endif } bool AsyncUDPPacket::isBroadcast() { +#if CONFIG_LWIP_IPV6 if (_localIp.type == IPADDR_TYPE_V6) { return false; } uint32_t ip = _localIp.u_addr.ip4.addr; +#else + uint32_t ip = _localIp.addr; +#endif return ip == 0xFFFFFFFF || ip == 0 || (ip & 0xFF000000) == 0xFF000000; } @@ -571,6 +602,7 @@ static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adap } netif = (struct netif *)nif; +#if CONFIG_LWIP_IPV6 if (addr->type == IPADDR_TYPE_V4) { if (join) { if (igmp_joingroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) { @@ -592,7 +624,19 @@ static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adap } } } +#else + if (join) { + if (igmp_joingroup_netif(netif, (const ip4_addr *)(addr))) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (igmp_leavegroup_netif(netif, (const ip4_addr *)(addr))) { + return ESP_ERR_INVALID_STATE; + } + } +#endif } else { +#if CONFIG_LWIP_IPV6 if (addr->type == IPADDR_TYPE_V4) { if (join) { if (igmp_joingroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) { @@ -614,6 +658,17 @@ static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adap } } } +#else + if (join) { + if (igmp_joingroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)(addr))) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (igmp_leavegroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)(addr))) { + return ESP_ERR_INVALID_STATE; + } + } +#endif } return ESP_OK; } @@ -722,18 +777,24 @@ size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr, } IPAddress AsyncUDP::listenIP() { +#if CONFIG_LWIP_IPV6 if (!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V4) { return IPAddress(); } return IPAddress(_pcb->remote_ip.u_addr.ip4.addr); +#else + return IPAddress(_pcb->remote_ip.addr); +#endif } +#if CONFIG_LWIP_IPV6 IPAddress AsyncUDP::listenIPv6() { if (!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V6) { return IPAddress(IPv6); } return IPAddress(IPv6, (const uint8_t *)_pcb->remote_ip.u_addr.ip6.addr, _pcb->remote_ip.u_addr.ip6.zone); } +#endif size_t AsyncUDP::write(const uint8_t *data, size_t len) { return writeTo(data, len, &(_pcb->remote_ip), _pcb->remote_port); diff --git a/libraries/AsyncUDP/src/AsyncUDP.h b/libraries/AsyncUDP/src/AsyncUDP.h index 160fb7b1515..cd96d852542 100644 --- a/libraries/AsyncUDP/src/AsyncUDP.h +++ b/libraries/AsyncUDP/src/AsyncUDP.h @@ -79,10 +79,14 @@ class AsyncUDPPacket : public Stream { tcpip_adapter_if_t interface(); IPAddress localIP(); +#if CONFIG_LWIP_IPV6 IPAddress localIPv6(); +#endif uint16_t localPort(); IPAddress remoteIP(); +#if CONFIG_LWIP_IPV6 IPAddress remoteIPv6(); +#endif uint16_t remotePort(); void remoteMac(uint8_t *mac); @@ -146,7 +150,9 @@ class AsyncUDP : public Print { size_t broadcast(AsyncUDPMessage &message); IPAddress listenIP(); +#if CONFIG_LWIP_IPV6 IPAddress listenIPv6(); +#endif bool connected(); esp_err_t lastErr(); operator bool(); 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/BLE/library.properties b/libraries/BLE/library.properties index 74dbf9c8514..32ad36b5f44 100644 --- a/libraries/BLE/library.properties +++ b/libraries/BLE/library.properties @@ -1,5 +1,5 @@ name=BLE -version=3.0.5 +version=3.1.0 author=Neil Kolban maintainer=Dariusz Krempa sentence=BLE functions for ESP32 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/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_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/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/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/BluetoothSerial/library.properties b/libraries/BluetoothSerial/library.properties index b7595ef3d1f..6db3a01bb19 100644 --- a/libraries/BluetoothSerial/library.properties +++ b/libraries/BluetoothSerial/library.properties @@ -1,5 +1,5 @@ name=BluetoothSerial -version=3.0.5 +version=3.1.0 author=Evandro Copercini maintainer=Evandro Copercini sentence=Simple UART to Classical Bluetooth bridge for ESP32 diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/libraries/BluetoothSerial/src/BluetoothSerial.cpp index bcb94db910f..3d00504c1b1 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"); @@ -705,9 +698,8 @@ 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); -#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/DNSServer/library.properties b/libraries/DNSServer/library.properties index fc1ce2d9107..077d9237f21 100644 --- a/libraries/DNSServer/library.properties +++ b/libraries/DNSServer/library.properties @@ -1,5 +1,5 @@ name=DNSServer -version=3.0.5 +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 d82b97dcf3d..bf75d618898 100644 --- a/libraries/EEPROM/library.properties +++ b/libraries/EEPROM/library.properties @@ -1,5 +1,5 @@ name=EEPROM -version=3.0.5 +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/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/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/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/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/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/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/keywords.txt b/libraries/ESP32/keywords.txt index 6cfd3fcab4c..866e76babd8 100644 --- a/libraries/ESP32/keywords.txt +++ b/libraries/ESP32/keywords.txt @@ -6,12 +6,50 @@ # Datatypes (KEYWORD1) ####################################### +Serial4 KEYWORD1 +espCtColor_t KEYWORD1 +espXyColor_t KEYWORD1 +espHsvColor_t KEYWORD1 +espRgbColor_t KEYWORD1 + ####################################### # Methods and Functions (KEYWORD2) ####################################### +espXYToRgbColor KEYWORD2 +espXYColorToRgb KEYWORD2 +espRgbColorToXYColor KEYWORD2 +espRgbToXYColor KEYWORD2 +espHsvColorToRgbColor KEYWORD2 +espHsvToRgbColor KEYWORD2 +espCTColorToRgbColor KEYWORD2 +espCTToRgbColor KEYWORD2 +espRgbColorToHsvColor KEYWORD2 +espRgbToHsvColor KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### RGB_BUILTIN LITERAL1 +HSV_BLACK LITERAL1 +HSV_WHITE LITERAL1 +HSV_RED LITERAL1 +HSV_YELLOW LITERAL1 +HSV_GREEN LITERAL1 +HSV_CYAN LITERAL1 +HSV_BLUE LITERAL1 +HSV_MAGENTA LITERAL1 +COOL_WHITE_COLOR_TEMPERATURE LITERAL1 +DAYLIGHT_WHITE_COLOR_TEMPERATURE LITERAL1 +WHITE_COLOR_TEMPERATURE LITERAL1 +SOFT_WHITE_COLOR_TEMPERATURE LITERAL1 +WARM_WHITE_COLOR_TEMPERATURE LITERAL1 +RGB_BLACK LITERAL1 +RGB_WHITE LITERAL1 +RGB_RED LITERAL1 +RGB_YELLOW LITERAL1 +RGB_GREEN LITERAL1 +RGB_CYAN LITERAL1 +RGB_BLUE LITERAL1 +RGB_MAGENTA LITERAL1 diff --git a/libraries/ESP32/library.properties b/libraries/ESP32/library.properties index 0f79f5cf010..1bb1ed21750 100644 --- a/libraries/ESP32/library.properties +++ b/libraries/ESP32/library.properties @@ -1,5 +1,5 @@ name=ESP32 -version=3.0.5 +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 d165941af0f..807f7daeb9d 100644 --- a/libraries/ESP_I2S/library.properties +++ b/libraries/ESP_I2S/library.properties @@ -1,5 +1,5 @@ name=ESP_I2S -version=3.0.5 +version=3.1.0 author=me-no-dev maintainer=me-no-dev sentence=Library for ESP I2S communication diff --git a/libraries/ESP_I2S/src/ESP_I2S.cpp b/libraries/ESP_I2S/src/ESP_I2S.cpp index 84050dfa6f8..0ac1e176dc8 100644 --- a/libraries/ESP_I2S/src/ESP_I2S.cpp +++ b/libraries/ESP_I2S/src/ESP_I2S.cpp @@ -7,12 +7,17 @@ #include "esp32-hal-periman.h" #include "wav_header.h" +#if ARDUINO_HAS_MP3_DECODER #include "mp3dec.h" +#endif #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, } +#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) \ { \ @@ -803,32 +808,36 @@ 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; } -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; + 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; @@ -1007,6 +1016,7 @@ void I2SClass::playWAV(uint8_t *data, size_t len) { write(data + WAVE_HEADER_SIZE + data_offset, data_chunk->subchunk_size); } +#if ARDUINO_HAS_MP3_DECODER bool I2SClass::playMP3(uint8_t *src, size_t src_len) { int16_t outBuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP]; uint8_t *readPtr = NULL; @@ -1044,5 +1054,6 @@ bool I2SClass::playMP3(uint8_t *src, size_t src_len) { MP3FreeDecoder(decoder); return true; } +#endif #endif /* SOC_I2S_SUPPORTED */ diff --git a/libraries/ESP_I2S/src/ESP_I2S.h b/libraries/ESP_I2S/src/ESP_I2S.h index c83e3815ddb..b5c076bed04 100644 --- a/libraries/ESP_I2S/src/ESP_I2S.h +++ b/libraries/ESP_I2S/src/ESP_I2S.h @@ -1,5 +1,9 @@ #pragma once +#if defined __has_include && __has_include("mp3dec.h") +#define ARDUINO_HAS_MP3_DECODER 1 +#endif + #include "soc/soc_caps.h" #if SOC_I2S_SUPPORTED @@ -62,7 +66,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(); @@ -85,8 +89,10 @@ class I2SClass : public Stream { uint8_t *recordWAV(size_t rec_seconds, size_t *out_size); // Play short PCM WAV from memory void playWAV(uint8_t *data, size_t len); +#if ARDUINO_HAS_MP3_DECODER // Play short MP3 from memory bool playMP3(uint8_t *src, size_t src_len); +#endif private: esp_err_t last_error; 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 618e46bd244..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,6 +1,5 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "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 618e46bd244..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,6 +1,5 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "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 618e46bd244..36babb82730 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json @@ -1,6 +1,5 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "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 618e46bd244..36babb82730 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json @@ -1,6 +1,5 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" ] } diff --git a/libraries/ESP_NOW/library.properties b/libraries/ESP_NOW/library.properties index 262454bb069..42876f47f95 100644 --- a/libraries/ESP_NOW/library.properties +++ b/libraries/ESP_NOW/library.properties @@ -1,5 +1,5 @@ name=ESP_NOW -version=3.0.5 +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_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp index 69b8ddd96a5..6fd3ff0a0b1 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -1,3 +1,8 @@ +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#warning "ESP-NOW is only supported in SoCs with native Wi-Fi support" +#else + #include "ESP32_NOW.h" #include #include "esp_system.h" @@ -406,3 +411,5 @@ size_t ESP_NOW_Peer::send(const uint8_t *data, int len) { ESP_NOW_Peer::operator bool() const { return added; } + +#endif diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h index 1bbcabb2557..efba9243aee 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.h +++ b/libraries/ESP_NOW/src/ESP32_NOW.h @@ -1,5 +1,10 @@ #pragma once +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#warning "ESP-NOW is only supported in SoCs with native Wi-Fi support" +#else + #include "esp_wifi_types.h" #include "Print.h" #include "esp_now.h" @@ -77,3 +82,5 @@ class ESP_NOW_Peer { }; extern ESP_NOW_Class ESP_NOW; + +#endif diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index 17740d1331a..5603da2ba13 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -1,3 +1,8 @@ +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#warning "ESP-NOW is only supported in SoCs with native Wi-Fi support" +#else + #include "ESP32_NOW_Serial.h" #include #include "esp_now.h" @@ -277,3 +282,5 @@ void ESP_NOW_Serial_Class::onSent(bool success) { } } } + +#endif diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.h b/libraries/ESP_NOW/src/ESP32_NOW_Serial.h index b1f41456320..7cc43d85ef8 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.h +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.h @@ -1,5 +1,10 @@ #pragma once +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#warning "ESP-NOW is only supported in SoCs with native Wi-Fi support" +#else + #include "esp_wifi_types.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -48,3 +53,5 @@ class ESP_NOW_Serial_Class : public Stream, public ESP_NOW_Peer { void onReceive(const uint8_t *data, size_t len, bool broadcast); void onSent(bool success); }; + +#endif diff --git a/libraries/ESP_SR/examples/Basic/ci.json b/libraries/ESP_SR/examples/Basic/ci.json index c9b0955f8f2..c395378f45e 100644 --- a/libraries/ESP_SR/examples/Basic/ci.json +++ b/libraries/ESP_SR/examples/Basic/ci.json @@ -12,6 +12,7 @@ "esp32c3": false, "esp32c6": false, "esp32h2": false, + "esp32p4": false, "esp32s2": false } } diff --git a/libraries/ESP_SR/library.properties b/libraries/ESP_SR/library.properties index 6f0d447d29b..a81cff2fe9d 100644 --- a/libraries/ESP_SR/library.properties +++ b/libraries/ESP_SR/library.properties @@ -1,5 +1,5 @@ name=ESP_SR -version=3.0.5 +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 32a2fe24695..4f65114fd0b 100644 --- a/libraries/ESPmDNS/library.properties +++ b/libraries/ESPmDNS/library.properties @@ -1,5 +1,5 @@ name=ESPmDNS -version=3.0.5 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 mDNS Library diff --git a/libraries/ESPmDNS/src/ESPmDNS.cpp b/libraries/ESPmDNS/src/ESPmDNS.cpp index 546de43c20a..4c15ed3a5dd 100644 --- a/libraries/ESPmDNS/src/ESPmDNS.cpp +++ b/libraries/ESPmDNS/src/ESPmDNS.cpp @@ -39,6 +39,7 @@ License (MIT license): #endif #include "ESPmDNS.h" +#ifdef CONFIG_MDNS_MAX_INTERFACES #include #include "esp_mac.h" #include "soc/soc_caps.h" @@ -391,3 +392,5 @@ String MDNSResponder::txtKey(int idx, int txtIdx) { } MDNSResponder MDNS; + +#endif /* CONFIG_MDNS_MAX_INTERFACES */ diff --git a/libraries/ESPmDNS/src/ESPmDNS.h b/libraries/ESPmDNS/src/ESPmDNS.h index 04ac382cfdc..0336f476efe 100644 --- a/libraries/ESPmDNS/src/ESPmDNS.h +++ b/libraries/ESPmDNS/src/ESPmDNS.h @@ -41,6 +41,9 @@ License (MIT license): #ifndef ESP32MDNS_H #define ESP32MDNS_H +#include "sdkconfig.h" +#ifdef CONFIG_MDNS_MAX_INTERFACES + #include "Arduino.h" #include "mdns.h" #include "esp_interface.h" @@ -125,4 +128,5 @@ class MDNSResponder { extern MDNSResponder MDNS; +#endif /* CONFIG_MDNS_MAX_INTERFACES */ #endif //ESP32MDNS_H 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_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/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_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/library.properties b/libraries/Ethernet/library.properties index ea92455fe37..70aa24ec4aa 100644 --- a/libraries/Ethernet/library.properties +++ b/libraries/Ethernet/library.properties @@ -1,5 +1,5 @@ name=Ethernet -version=3.0.5 +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/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index 4d215d80034..fa8a2b97122 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -22,6 +22,7 @@ #define ARDUINO_CORE_BUILD #include "ETH.h" +#if CONFIG_ETH_ENABLED #include "esp_system.h" #include "esp_event.h" #include "esp_eth.h" @@ -30,7 +31,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" @@ -72,6 +75,7 @@ static void onEthConnected(arduino_event_id_t event, arduino_event_info_t info) log_e("Could not find ETH interface with that handle!"); return; } +#if CONFIG_LWIP_IPV6 if (_ethernets[index]->getStatusBits() & ESP_NETIF_WANT_IP6_BIT) { esp_err_t err = esp_netif_create_ip6_linklocal(_ethernets[index]->netif()); if (err != ESP_OK) { @@ -80,6 +84,7 @@ static void onEthConnected(arduino_event_id_t event, arduino_event_info_t info) log_v("Enabled IPv6 Link Local on %s", _ethernets[index]->desc()); } } +#endif } } @@ -147,6 +152,42 @@ void ETHClass::setTaskStackSize(size_t size) { } #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 +// 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; if (_eth_index > 2) { @@ -170,14 +211,23 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i Network.begin(); _ethernets[_eth_index] = this; - eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); +#if CONFIG_IDF_TARGET_ESP32 +#undef DEFAULT_RMII_CLK_GPIO +#define DEFAULT_RMII_CLK_GPIO (emac_rmii_clock_gpio_t)(0) +#endif + + 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; - mac_config.smi_mdc_gpio_num = digitalPinToGPIONumber(mdc); - mac_config.smi_mdio_gpio_num = digitalPinToGPIONumber(mdio); +#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); _pin_mcd = digitalPinToGPIONumber(mdc); _pin_mdio = digitalPinToGPIONumber(mdio); @@ -893,7 +943,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); @@ -1007,3 +1057,5 @@ size_t ETHClass::printDriverInfo(Print &out) const { } ETHClass ETH; + +#endif /* CONFIG_ETH_ENABLED */ diff --git a/libraries/Ethernet/src/ETH.h b/libraries/Ethernet/src/ETH.h index 14d2d042614..582835cf8ac 100644 --- a/libraries/Ethernet/src/ETH.h +++ b/libraries/Ethernet/src/ETH.h @@ -18,6 +18,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "sdkconfig.h" +#if CONFIG_ETH_ENABLED + #ifndef _ETH_H_ #define _ETH_H_ @@ -75,6 +78,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 +92,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 @@ -223,3 +252,4 @@ class ETHClass : public NetworkInterface { extern ETHClass ETH; #endif /* _ETH_H_ */ +#endif /* CONFIG_ETH_ENABLED */ diff --git a/libraries/FFat/library.properties b/libraries/FFat/library.properties index e01f1e2f2a7..dae11e43aaf 100644 --- a/libraries/FFat/library.properties +++ b/libraries/FFat/library.properties @@ -1,5 +1,5 @@ name=FFat -version=3.0.5 +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/FFat/src/FFat.cpp b/libraries/FFat/src/FFat.cpp index 506cc70be46..4a2274b2fdb 100644 --- a/libraries/FFat/src/FFat.cpp +++ b/libraries/FFat/src/FFat.cpp @@ -46,7 +46,11 @@ 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 +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 + .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/FS/library.properties b/libraries/FS/library.properties index 9bdcdb83573..009383ab0c8 100644 --- a/libraries/FS/library.properties +++ b/libraries/FS/library.properties @@ -1,5 +1,5 @@ name=FS -version=3.0.5 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 File System diff --git a/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino b/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino index 7f1d1dd3575..d8b66ac19d9 100644 --- a/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino +++ b/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino @@ -3,6 +3,12 @@ /*|TESTED BOARDS: Devkit v1 DOIT, Devkitc v4 |*/ /*|CORE: June 2018 |*/ /*|----------------------------------------------------------|*/ + +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#error "WPA-Enterprise is only supported in SoCs with native Wi-Fi support" +#endif + #include #include #if __has_include("esp_eap_client.h") diff --git a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json index 618e46bd244..04eb62b977a 100644 --- a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json +++ b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json @@ -1,6 +1,6 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" ] } diff --git a/libraries/HTTPClient/library.properties b/libraries/HTTPClient/library.properties index 2c1e160efee..203b8929d30 100644 --- a/libraries/HTTPClient/library.properties +++ b/libraries/HTTPClient/library.properties @@ -1,5 +1,5 @@ name=HTTPClient -version=3.0.5 +version=3.1.0 author=Markus Sattler maintainer=Markus Sattler sentence=HTTP Client for ESP32 diff --git a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json index 618e46bd244..cbdd28f773d 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_any": [ "CONFIG_SOC_WIFI_SUPPORTED=y", "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" diff --git a/libraries/HTTPUpdate/library.properties b/libraries/HTTPUpdate/library.properties index aca3f392795..ac903dd71cf 100644 --- a/libraries/HTTPUpdate/library.properties +++ b/libraries/HTTPUpdate/library.properties @@ -1,5 +1,5 @@ name=HTTPUpdate -version=3.0.5 +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 03f6b299bf9..b26bd2cad7b 100644 --- a/libraries/HTTPUpdateServer/library.properties +++ b/libraries/HTTPUpdateServer/library.properties @@ -1,5 +1,5 @@ name=HTTPUpdateServer -version=3.0.5 +version=3.1.0 author=Hristo Kapanakov maintainer= sentence=Simple HTTP Update server based on the WebServer diff --git a/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino b/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino index 52019a703b7..7102dfb19af 100644 --- a/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino +++ b/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino @@ -36,6 +36,7 @@ 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); + //ToDo: find better way to crash abort(); } } diff --git a/libraries/Insights/library.properties b/libraries/Insights/library.properties index a948dbe7ad1..af213a1e70d 100644 --- a/libraries/Insights/library.properties +++ b/libraries/Insights/library.properties @@ -1,5 +1,5 @@ name=ESP Insights -version=3.0.5 +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 fac629fab31..86c4c43eeca 100644 --- a/libraries/LittleFS/library.properties +++ b/libraries/LittleFS/library.properties @@ -1,5 +1,5 @@ name=LittleFS -version=3.0.5 +version=3.1.0 author= maintainer= sentence=LittleFS for esp32 diff --git a/libraries/LittleFS/src/LittleFS.cpp b/libraries/LittleFS/src/LittleFS.cpp index e0e71aacf9c..e86caeb74cc 100644 --- a/libraries/LittleFS/src/LittleFS.cpp +++ b/libraries/LittleFS/src/LittleFS.cpp @@ -12,18 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "LittleFS.h" + +#ifdef CONFIG_LITTLEFS_PAGE_SIZE #include "vfs_api.h" extern "C" { #include #include #include -} -#include "sdkconfig.h" -#include "LittleFS.h" - -#ifdef CONFIG_LITTLEFS_PAGE_SIZE -extern "C" { #include "esp_littlefs.h" } @@ -125,4 +122,4 @@ size_t LittleFSFS::usedBytes() { } LittleFSFS LittleFS; -#endif +#endif /* CONFIG_LITTLEFS_PAGE_SIZE */ diff --git a/libraries/LittleFS/src/LittleFS.h b/libraries/LittleFS/src/LittleFS.h index 47220b30b33..da4ab7d1f6f 100644 --- a/libraries/LittleFS/src/LittleFS.h +++ b/libraries/LittleFS/src/LittleFS.h @@ -14,6 +14,10 @@ #ifndef _LITTLEFS_H_ #define _LITTLEFS_H_ +#include "sdkconfig.h" + +#ifdef CONFIG_LITTLEFS_PAGE_SIZE + #include "FS.h" namespace fs { @@ -36,4 +40,5 @@ class LittleFSFS : public FS { extern fs::LittleFSFS LittleFS; +#endif /* CONFIG_LITTLEFS_PAGE_SIZE */ #endif diff --git a/libraries/Matter/examples/MatterColorLight/MatterColorLight.ino b/libraries/Matter/examples/MatterColorLight/MatterColorLight.ino new file mode 100644 index 00000000000..dd1724f602d --- /dev/null +++ b/libraries/Matter/examples/MatterColorLight/MatterColorLight.ino @@ -0,0 +1,180 @@ +// 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. + +// Matter Manager +#include +#include +#include + +// List of Matter Endpoints for this Node +// Color Light Endpoint +MatterColorLight ColorLight; + +// 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 + +// it will keep last OnOff & HSV Color state stored, using Preferences +Preferences matterPref; +const char *onOffPrefKey = "OnOff"; +const char *hsvColorPrefKey = "HSV"; + +// set your board RGB LED pin here +#ifdef RGB_BUILTIN +const uint8_t ledPin = RGB_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 RGB LED pin" +#endif + +// set your board USER BUTTON pin here +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Set the RGB LED Light based on the current state of the Color Light +bool setLightState(bool state, espHsvColor_t colorHSV) { + + if (state) { +#ifdef RGB_BUILTIN + espRgbColor_t rgbColor = espHsvColorToRgbColor(colorHSV); + // set the RGB LED + rgbLedWrite(ledPin, rgbColor.r, rgbColor.g, rgbColor.b); +#else + // No Color RGB LED, just use the HSV value (brightness) to control the LED + analogWrite(ledPin, colorHSV.v); +#endif + } else { + digitalWrite(ledPin, LOW); + } + // store last HSV Color and OnOff state for when the Light is restarted / power goes off + matterPref.putBool(onOffPrefKey, state); + matterPref.putUInt(hsvColorPrefKey, colorHSV.h << 16 | colorHSV.s << 8 | colorHSV.v); + // This callback must return the success state to Matter core + return true; +} + +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); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // 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 + matterPref.begin("MatterPrefs", false); + // default OnOff state is ON if not stored before + bool lastOnOffState = matterPref.getBool(onOffPrefKey, true); + // default HSV color is blue HSV(169, 254, 254) + uint32_t prefHsvColor = matterPref.getUInt(hsvColorPrefKey, 169 << 16 | 254 << 8 | 254); + espHsvColor_t lastHsvColor = {uint8_t(prefHsvColor >> 16), uint8_t(prefHsvColor >> 8), uint8_t(prefHsvColor)}; + ColorLight.begin(lastOnOffState, lastHsvColor); + // set the callback function to handle the Light state change + ColorLight.onChange(setLightState); + + // lambda functions are used to set the attribute change callbacks + ColorLight.onChangeOnOff([](bool state) { + Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF"); + return true; + }); + ColorLight.onChangeColorHSV([](HsvColor_t hsvColor) { + Serial.printf("Light HSV Color changed to (%d,%d,%d)\r\n", hsvColor.h, hsvColor.s, hsvColor.v); + return true; + }); + + // 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 | RGB Color: (%d,%d,%d) \r\n", ColorLight ? "ON" : "OFF", ColorLight.getColorRGB().r, ColorLight.getColorRGB().g, + ColorLight.getColorRGB().b + ); + // configure the Light based on initial on-off state and its color + ColorLight.updateAccessory(); + } +} + +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 | RGB Color: (%d,%d,%d) \r\n", ColorLight ? "ON" : "OFF", ColorLight.getColorRGB().r, ColorLight.getColorRGB().g, + ColorLight.getColorRGB().b + ); + // configure the Light based on initial on-off state and its color + ColorLight.updateAccessory(); + 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 (digitalRead(buttonPin) == HIGH && button_state && time_diff > debouceTime) { + // Toggle button is released - toggle the light + Serial.println("User button released. Toggling Light!"); + ColorLight.toggle(); // Matter Controller also can see the change + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + ColorLight = false; // turn the light off + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } +} diff --git a/libraries/Matter/examples/MatterColorLight/ci.json b/libraries/Matter/examples/MatterColorLight/ci.json new file mode 100644 index 00000000000..d5f63487506 --- /dev/null +++ b/libraries/Matter/examples/MatterColorLight/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/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino new file mode 100644 index 00000000000..0e93ed6d155 --- /dev/null +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -0,0 +1,72 @@ +// 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. + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +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); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // 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..9c3dcf05a83 --- /dev/null +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -0,0 +1,137 @@ +// 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. + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// There will be 3 On/Off Light Endpoints in the same Node +MatterOnOffLight Light1; +MatterDimmableLight Light2; +MatterColorLight Light3; + +// 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 + +// set your board USER BUTTON pin here - USED to decommission the Matter Node +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Matter Protocol Endpoint Callback for each Light Accessory +bool setLightOnOff1(bool state) { + Serial.printf("Light1 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +bool setLightOnOff2(bool state) { + Serial.printf("Light2 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +bool setLightOnOff3(bool state) { + Serial.printf("Light3 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + delay(500); + + // Initialize all 3 Matter EndPoints + Light1.begin(); + Light2.begin(); + Light3.begin(); + Light1.onChangeOnOff(setLightOnOff1); + Light2.onChangeOnOff(setLightOnOff2); + Light3.onChangeOnOff(setLightOnOff3); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); +} + +void loop() { + static uint32_t timeCounter = 0; + + // 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 5 seconds + if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s + Serial.println("======================"); + Serial.printf("Matter Light #1 is %s\r\n", Light1.getOnOff() ? "ON" : "OFF"); + Serial.printf("Matter Light #2 is %s\r\n", Light2.getOnOff() ? "ON" : "OFF"); + Serial.printf("Matter Light #3 is %s\r\n", Light3.getOnOff() ? "ON" : "OFF"); + } + + // 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. + } + + if (digitalRead(buttonPin) == HIGH && button_state) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + delay(500); +} 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/MatterContactSensor/MatterContactSensor.ino b/libraries/Matter/examples/MatterContactSensor/MatterContactSensor.ino new file mode 100644 index 00000000000..e27f70e613d --- /dev/null +++ b/libraries/Matter/examples/MatterContactSensor/MatterContactSensor.ino @@ -0,0 +1,152 @@ +// 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. + +/* + * This example is an example code that will create a Matter Device which can be + * commissioned and controlled from a Matter Environment APP. + * Additionally the ESP32 will send debug messages indicating the Matter activity. + * Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages. + * + * The example will create a Matter Contact Sensor Device. + * The Contact Sensor state can be toggled by pressing the onboard button. + * The Contact Sensor state will be indicated by the onboard LED. + * The Contact Sensor state will be simulated to change every 20 seconds. + * + * The onboard button can be kept pressed for 5 seconds to decommission the Matter Node. + * The example will also show the manual commissioning code and QR code to be used in the Matter environment. + * + */ + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Matter Contact Sensor Endpoint +MatterContactSensor ContactSensor; + +// 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 + +// LED will be used to indicate the Contact Sensor state +// set your board RGB LED pin here +#ifdef RGB_BUILTIN +const uint8_t ledPin = RGB_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 RGB LED pin" +#endif + +// set your board USER BUTTON pin here - decommissioning and Manual Contact Sensor toggle button +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + // The button will also be used to manually toggle the Contact Sensor state + pinMode(buttonPin, INPUT_PULLUP); + // Initialize the LED (light) GPIO and Matter End Point + pinMode(ledPin, OUTPUT); + + Serial.begin(115200); + + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); + + // set initial contact sensor state as false (default) + ContactSensor.begin(); + digitalWrite(ledPin, LOW); // LED OFF + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + // Check Matter Accessory 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 Contact Sensor 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."); + } +} + +bool simulatedHWContactSensor() { + // Simulated Contact Sensor + static bool contactState = false; + static uint32_t lastTime = 0; + + // Simulate a Contact Sensor state change every 20 seconds + if (millis() - lastTime > 20000) { + contactState = !contactState; + lastTime = millis(); + } + return contactState; +} + +void loop() { + // 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. + } + + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) { + button_state = false; // released + // button is released - toggle Contact State (Open/Closed) + ContactSensor.setContact(!ContactSensor.getContact()); // same as ContactSensor = !ContactSensor; + Serial.printf("User button released. Setting the Contact Sensor to %s.\r\n", ContactSensor ? "Closed" : "Open"); + // LED will indicate the Contact Sensor state + if (ContactSensor) { + digitalWrite(ledPin, HIGH); // LED ON + } else { + digitalWrite(ledPin, LOW); // LED OFF + } + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Generic Switch Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + // Simulated Contact Sensor + ContactSensor.setContact(simulatedHWContactSensor()); + + delay(50); +} diff --git a/libraries/Matter/examples/MatterContactSensor/ci.json b/libraries/Matter/examples/MatterContactSensor/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterContactSensor/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/MatterDimmableLight/MatterDimmableLight.ino b/libraries/Matter/examples/MatterDimmableLight/MatterDimmableLight.ino new file mode 100644 index 00000000000..cb8b8b6f17f --- /dev/null +++ b/libraries/Matter/examples/MatterDimmableLight/MatterDimmableLight.ino @@ -0,0 +1,169 @@ +// 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. + +// Matter Manager +#include +#include +#include + +// List of Matter Endpoints for this Node +// Dimmable Light Endpoint +MatterDimmableLight DimmableLight; + +// 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 + +// it will keep last OnOff & Brightness state stored, using Preferences +Preferences matterPref; +const char *onOffPrefKey = "OnOff"; +const char *brightnessPrefKey = "Brightness"; + +// set your board RGB LED pin here +#ifdef RGB_BUILTIN +const uint8_t ledPin = RGB_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 RGB LED pin" +#endif + +// set your board USER BUTTON pin here +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Set the RGB LED Light based on the current state of the Dimmable Light +bool setLightState(bool state, uint8_t brightness) { + if (state) { +#ifdef RGB_BUILTIN + rgbLedWrite(ledPin, brightness, brightness, brightness); +#else + analogWrite(ledPin, brightness); +#endif + } else { + digitalWrite(ledPin, LOW); + } + // store last Brightness and OnOff state for when the Light is restarted / power goes off + matterPref.putUChar(brightnessPrefKey, brightness); + matterPref.putBool(onOffPrefKey, state); + // This callback must return the success state to Matter core + return true; +} + +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); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // 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 + matterPref.begin("MatterPrefs", false); + // default OnOff state is ON if not stored before + bool lastOnOffState = matterPref.getBool(onOffPrefKey, true); + // default brightness ~= 6% (15/255) + uint8_t lastBrightness = matterPref.getUChar(brightnessPrefKey, 15); + DimmableLight.begin(lastOnOffState, lastBrightness); + // set the callback function to handle the Light state change + DimmableLight.onChange(setLightState); + + // lambda functions are used to set the attribute change callbacks + DimmableLight.onChangeOnOff([](bool state) { + Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF"); + return true; + }); + DimmableLight.onChangeBrightness([](uint8_t level) { + Serial.printf("Light Brightness changed to %d\r\n", level); + return true; + }); + + // 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 | brightness: %d\r\n", DimmableLight ? "ON" : "OFF", DimmableLight.getBrightness()); + // configure the Light based on initial on-off state and brightness + DimmableLight.updateAccessory(); + } +} + +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 | brightness: %d\r\n", DimmableLight ? "ON" : "OFF", DimmableLight.getBrightness()); + // configure the Light based on initial on-off state and brightness + DimmableLight.updateAccessory(); + 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 (digitalRead(buttonPin) == HIGH && button_state && time_diff > debouceTime) { + // Toggle button is released - toggle the light + Serial.println("User button released. Toggling Light!"); + DimmableLight.toggle(); // Matter Controller also can see the change + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + DimmableLight = false; // turn the light off + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } +} diff --git a/libraries/Matter/examples/MatterDimmableLight/ci.json b/libraries/Matter/examples/MatterDimmableLight/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterDimmableLight/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/MatterEnhancedColorLight/MatterEnhancedColorLight.ino b/libraries/Matter/examples/MatterEnhancedColorLight/MatterEnhancedColorLight.ino new file mode 100644 index 00000000000..bd2d13899ca --- /dev/null +++ b/libraries/Matter/examples/MatterEnhancedColorLight/MatterEnhancedColorLight.ino @@ -0,0 +1,202 @@ +// 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. + +// Matter Manager +#include +#include +#include + +// List of Matter Endpoints for this Node +// Color Light Endpoint +MatterEnhancedColorLight EnhancedColorLight; + +// 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 + +// It will use HSV color to control all Matter Attribute Changes +HsvColor_t currentHSVColor = {0, 0, 0}; + +// it will keep last OnOff & HSV Color state stored, using Preferences +Preferences matterPref; +const char *onOffPrefKey = "OnOff"; +const char *hsvColorPrefKey = "HSV"; + +// set your board RGB LED pin here +#ifdef RGB_BUILTIN +const uint8_t ledPin = RGB_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 RGB LED pin" +#endif + +// set your board USER BUTTON pin here +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Set the RGB LED Light based on the current state of the Enhanced Color Light +bool setLightState(bool state, espHsvColor_t colorHSV, uint8_t brighteness, uint16_t temperature_Mireds) { + + if (state) { +#ifdef RGB_BUILTIN + // currentHSVColor keeps final color result + espRgbColor_t rgbColor = espHsvColorToRgbColor(currentHSVColor); + // set the RGB LED + rgbLedWrite(ledPin, rgbColor.r, rgbColor.g, rgbColor.b); +#else + // No Color RGB LED, just use the HSV value (brightness) to control the LED + analogWrite(ledPin, colorHSV.v); +#endif + } else { + digitalWrite(ledPin, LOW); + } + // store last HSV Color and OnOff state for when the Light is restarted / power goes off + matterPref.putBool(onOffPrefKey, state); + matterPref.putUInt(hsvColorPrefKey, currentHSVColor.h << 16 | currentHSVColor.s << 8 | currentHSVColor.v); + // This callback must return the success state to Matter core + return true; +} + +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); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // 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 + matterPref.begin("MatterPrefs", false); + // default OnOff state is ON if not stored before + bool lastOnOffState = matterPref.getBool(onOffPrefKey, true); + // default HSV color is (21, 216, 25) - Warm White Color at 10% intensity + uint32_t prefHsvColor = matterPref.getUInt(hsvColorPrefKey, 21 << 16 | 216 << 8 | 25); + currentHSVColor = {uint8_t(prefHsvColor >> 16), uint8_t(prefHsvColor >> 8), uint8_t(prefHsvColor)}; + EnhancedColorLight.begin(lastOnOffState, currentHSVColor); + // set the callback function to handle the Light state change + EnhancedColorLight.onChange(setLightState); + + // lambda functions are used to set the attribute change callbacks + EnhancedColorLight.onChangeOnOff([](bool state) { + Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF"); + return true; + }); + EnhancedColorLight.onChangeColorTemperature([](uint16_t colorTemperature) { + Serial.printf("Light Color Temperature changed to %d\r\n", colorTemperature); + // get correspondent Hue and Saturation of the color temperature + HsvColor_t hsvTemperature = espRgbColorToHsvColor(espCTToRgbColor(colorTemperature)); + // keep previous the brightness and just change the Hue and Saturation + currentHSVColor.h = hsvTemperature.h; + currentHSVColor.s = hsvTemperature.s; + return true; + }); + EnhancedColorLight.onChangeBrightness([](uint8_t brightness) { + Serial.printf("Light brightness changed to %d\r\n", brightness); + // change current brightness (HSV value) + currentHSVColor.v = brightness; + return true; + }); + EnhancedColorLight.onChangeColorHSV([](HsvColor_t hsvColor) { + Serial.printf("Light HSV Color changed to (%d,%d,%d)\r\n", hsvColor.h, hsvColor.s, hsvColor.v); + // keep the current brightness and just change Hue and Saturation + currentHSVColor.h = hsvColor.h; + currentHSVColor.s = hsvColor.s; + return true; + }); + + // 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 | RGB Color: (%d,%d,%d) \r\n", EnhancedColorLight ? "ON" : "OFF", EnhancedColorLight.getColorRGB().r, + EnhancedColorLight.getColorRGB().g, EnhancedColorLight.getColorRGB().b + ); + // configure the Light based on initial on-off state and its color + EnhancedColorLight.updateAccessory(); + } +} + +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 | RGB Color: (%d,%d,%d) \r\n", EnhancedColorLight ? "ON" : "OFF", EnhancedColorLight.getColorRGB().r, + EnhancedColorLight.getColorRGB().g, EnhancedColorLight.getColorRGB().b + ); + // configure the Light based on initial on-off state and its color + EnhancedColorLight.updateAccessory(); + 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!"); + EnhancedColorLight.toggle(); // Matter Controller also can see the change + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + EnhancedColorLight = false; // turn the light off + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } +} diff --git a/libraries/Matter/examples/MatterEnhancedColorLight/ci.json b/libraries/Matter/examples/MatterEnhancedColorLight/ci.json new file mode 100644 index 00000000000..0665800b12b --- /dev/null +++ b/libraries/Matter/examples/MatterEnhancedColorLight/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/MatterFan/MatterFan.ino b/libraries/Matter/examples/MatterFan/MatterFan.ino new file mode 100644 index 00000000000..3dc0c89fcf4 --- /dev/null +++ b/libraries/Matter/examples/MatterFan/MatterFan.ino @@ -0,0 +1,198 @@ +// 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. + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Fan Endpoint - On/Off control + Speed Percent Control + Fan Modes +MatterFan Fan; + +// 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 + +// set your board USER BUTTON pin here - used for toggling On/Off and decommission the Matter Node +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission + +// set your board Analog Pin here - used for changing the Fan speed +const uint8_t analogPin = A0; // Analog Pin depends on each board + +// set your board PWM Pin here - used for controlling the Fan speed (DC motor example) +// for this example, it will use the builtin board RGB LED to simulate the Fan DC motor using its brightness +#ifdef RGB_BUILTIN +const uint8_t dcMotorPin = RGB_BUILTIN; +#else +const uint8_t dcMotorPin = 2; // Set your pin here if your board has not defined LED_BUILTIN +#warning "Do not forget to set the RGB LED pin" +#endif + +void fanDCMotorDrive(bool fanState, uint8_t speedPercent) { + // drive the Fan DC motor + if (fanState == false) { + // turn off the Fan + digitalWrite(dcMotorPin, LOW); + } else { + // set the Fan speed + uint8_t fanDCMotorPWM = map(speedPercent, 0, 100, 0, 255); +#ifdef RGB_BUILTIN + rgbLedWrite(dcMotorPin, fanDCMotorPWM, fanDCMotorPWM, fanDCMotorPWM); +#else + analogWrite(dcMotorPin, fanDCMotorPWM); +#endif + } +} + +void setup() { + // Initialize the USER BUTTON (Boot button) GPIO that will toggle the Fan (On/Off) and decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + // Initialize the Analog Pin A0 used to read input voltage and to set the Fan speed accordingly + pinMode(analogPin, INPUT); + analogReadResolution(10); // 10 bits resolution reading 0..1023 + // Initialize the PWM output pin for a Fan DC motor + pinMode(dcMotorPin, OUTPUT); + + Serial.begin(115200); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // 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); + + // On Boot or Reset, Fan is set at 0% speed, OFF, changing between OFF, ON, SMART and HIGH + Fan.begin(0, MatterFan::FAN_MODE_OFF, MatterFan::FAN_MODE_SEQ_OFF_HIGH); + + // callback functions would control Fan motor + // the Matter Controller will send new data whenever the User APP or Automation request + + // single feature callbacks take place before the generic (all features) callback + // This callback will be executed whenever the speed percent matter attribute is updated + Fan.onChangeSpeedPercent([](uint8_t speedPercent) { + // setting speed to Zero, while the Fan is ON, shall turn the Fan OFF + if (speedPercent == MatterFan::OFF_SPEED && Fan.getMode() != MatterFan::FAN_MODE_OFF) { + // ATTR_SET do not update the attribute, just SET it to avoid infinite loop + return Fan.setOnOff(false, Fan.ATTR_SET); + } + // changing the speed to higher than Zero, while the Fan is OFF, shall turn the Fan ON + if (speedPercent > MatterFan::OFF_SPEED && Fan.getMode() == MatterFan::FAN_MODE_OFF) { + // ATTR_SET do not update the attribute, just SET it to avoid infinite loop + return Fan.setOnOff(true, Fan.ATTR_SET); + } + // for other case, just return true + return true; + }); + + // This callback will be executed whenever the fan mode matter attribute is updated + // This will take action when user APP starts the Fan by changing the mode + Fan.onChangeMode([](MatterFan::FanMode_t fanMode) { + // when the Fan is turned ON using Mode Selection, while it is OFF, shall start it by setting the speed to 50% + if (Fan.getSpeedPercent() == MatterFan::OFF_SPEED && fanMode != MatterFan::FAN_MODE_OFF) { + Serial.printf("Fan set to %s mode -- speed percentage will go to 50%%\r\n", Fan.getFanModeString(fanMode)); + // ATTR_SET do not update the attribute, just SET it to avoid infinite loop + return Fan.setSpeedPercent(50, Fan.ATTR_SET); + } + return true; + }); + + // Generic callback will be executed as soon as a single feature callback is done + // In this example, it will just print status messages + Fan.onChange([](MatterFan::FanMode_t fanMode, uint8_t speedPercent) { + // just report state + Serial.printf("Fan State: Mode %s | %d%% speed.\r\n", Fan.getFanModeString(fanMode), speedPercent); + // drive the Fan DC motor + fanDCMotorDrive(fanMode != MatterFan::FAN_MODE_OFF, speedPercent); + // returns success + return true; + }); + + // 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."); + } +} + +void loop() { + // Check Matter Accessory 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 Generic Switch 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."); + } + + // A builtin button is used to trigger and send a command to the Matter Controller + // 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 smart button 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 + // button is released - toggle Fan On/Off + Fan.toggle(); + Serial.printf("User button released. Setting the Fan %s.\r\n", Fan > 0 ? "ON" : "OFF"); + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Generic Switch Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + // checks Analog pin and adjust the speed only if it has changed + static int lastRead = 0; + // analog values (0..1023) / 103 => mapped into 10 steps (0..9) + int anaVal = analogRead(analogPin) / 103; + if (lastRead != anaVal) { + // speed percent moves in steps of 10. Range is 10..100 + if (Fan.setSpeedPercent((anaVal + 1) * 10)) { + lastRead = anaVal; + } + } +} diff --git a/libraries/Matter/examples/MatterFan/ci.json b/libraries/Matter/examples/MatterFan/ci.json new file mode 100644 index 00000000000..0665800b12b --- /dev/null +++ b/libraries/Matter/examples/MatterFan/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/MatterHumiditySensor/MatterHumiditySensor.ino b/libraries/Matter/examples/MatterHumiditySensor/MatterHumiditySensor.ino new file mode 100644 index 00000000000..3fcab46c565 --- /dev/null +++ b/libraries/Matter/examples/MatterHumiditySensor/MatterHumiditySensor.ino @@ -0,0 +1,130 @@ +// 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. + +/* + * This example is an example code that will create a Matter Device which can be + * commissioned and controlled from a Matter Environment APP. + * Additionally the ESP32 will send debug messages indicating the Matter activity. + * Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages. + */ + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Matter Humidity Sensor Endpoint +MatterHumiditySensor SimulatedHumiditySensor; + +// 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 + +// set your board USER BUTTON pin here - decommissioning button +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control - decommision the Matter Node +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Simulate a humidity sensor - add your preferred humidity sensor library code here +float getSimulatedHumidity() { + // The Endpoint implementation keeps an uint16_t as internal value information, + // which stores data in 1/100th of humidity percent + static float simulatedHumidityHWSensor = 10.0; + + // it will increase from 10% to 30% in 0.5% steps to simulate a humidity sensor + simulatedHumidityHWSensor = simulatedHumidityHWSensor + 0.5; + if (simulatedHumidityHWSensor > 30) { + simulatedHumidityHWSensor = 10; + } + + return simulatedHumidityHWSensor; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); + + // set initial humidity sensor measurement + // Simulated Sensor - it shall initially print 95% and then move to the 10% to 30% humidity range + SimulatedHumiditySensor.begin(95.00); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + // Check Matter Accessory 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 Humidity Sensor 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."); + } +} + +void loop() { + static uint32_t timeCounter = 0; + + // Print the current humidity value every 5s + if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s + // Print the current humidity value + Serial.printf("Current Humidity is %.02f%%\r\n", SimulatedHumiditySensor.getHumidity()); + // Update Humidity from the (Simulated) Hardware Sensor + // Matter APP shall display the updated humidity percent + SimulatedHumiditySensor.setHumidity(getSimulatedHumidity()); + } + + // 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. + } + + if (digitalRead(buttonPin) == HIGH && button_state) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + } + + delay(500); +} diff --git a/libraries/Matter/examples/MatterHumiditySensor/ci.json b/libraries/Matter/examples/MatterHumiditySensor/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterHumiditySensor/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/MatterMinimum/MatterMinimum.ino b/libraries/Matter/examples/MatterMinimum/MatterMinimum.ino new file mode 100644 index 00000000000..fa2599df6dd --- /dev/null +++ b/libraries/Matter/examples/MatterMinimum/MatterMinimum.ino @@ -0,0 +1,109 @@ +// 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. + +/* + * This example is the smallest code that will create a Matter Device which can be + * commissioned and controlled from a Matter Environment APP. + * It controls a GPIO that could be attached to a LED for visualization. + * Additionally the ESP32 will send debug messages indicating the Matter activity. + * Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages. + */ + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Single On/Off Light Endpoint - at least one per node +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 + +// Light GPIO that can be controlled by Matter APP +#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 +#endif + +// set your board USER BUTTON pin here - decommissioning button +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control - decommision the Matter Node +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Matter Protocol Endpoint (On/OFF Light) Callback +bool onOffLightCallback(bool state) { + digitalWrite(ledPin, state ? HIGH : LOW); + // This callback must return the success state to Matter core + return true; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + // Initialize the LED GPIO + pinMode(ledPin, OUTPUT); + + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + } + + // Initialize at least one Matter EndPoint + OnOffLight.begin(); + + // Associate a callback to the Matter Controller + OnOffLight.onChange(onOffLightCallback); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + if (!Matter.isDeviceCommissioned()) { + log_i("Matter Node is not commissioned yet."); + log_i("Initiate the device discovery in your Matter environment."); + log_i("Commission it to your Matter hub with the manual pairing code or QR code"); + log_i("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str()); + log_i("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str()); + } +} + +void loop() { + // 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. + } + + if (digitalRead(buttonPin) == HIGH && button_state) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + delay(500); +} diff --git a/libraries/Matter/examples/MatterMinimum/ci.json b/libraries/Matter/examples/MatterMinimum/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterMinimum/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/MatterOccupancySensor/MatterOccupancySensor.ino b/libraries/Matter/examples/MatterOccupancySensor/MatterOccupancySensor.ino new file mode 100644 index 00000000000..e88a9a8986b --- /dev/null +++ b/libraries/Matter/examples/MatterOccupancySensor/MatterOccupancySensor.ino @@ -0,0 +1,128 @@ +// 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. + +/* + * This example is an example code that will create a Matter Device which can be + * commissioned and controlled from a Matter Environment APP. + * Additionally the ESP32 will send debug messages indicating the Matter activity. + * Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages. + * + * The example will create a Matter Occupancy Sensor Device. + * The Occupancy Sensor will be simulated to change its state every 2 minutes. + * + * The onboard button can be kept pressed for 5 seconds to decommission the Matter Node. + * The example will also show the manual commissioning code and QR code to be used in the Matter environment. + * + */ + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Matter Occupancy Sensor Endpoint +MatterOccupancySensor OccupancySensor; + +// 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 + +// set your board USER BUTTON pin here - decommissioning only +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); + + // set initial occupancy sensor state as false and connected to a PIR sensor type (default) + OccupancySensor.begin(); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + // Check Matter Accessory 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 Occupancy Sensor 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."); + } +} + +bool simulatedHWOccupancySensor() { + // Simulated Occupancy Sensor + static bool occupancyState = false; + static uint32_t lastTime = millis(); + const uint32_t occupancyTimeout = 120000; // 2 minutes to toggle the state + + // Simulate a Occupancy Sensor state change every 2 minutes + if (millis() - lastTime > occupancyTimeout) { + occupancyState = !occupancyState; + lastTime = millis(); + } + return occupancyState; +} + +void loop() { + // 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. + } + + if (button_state && digitalRead(buttonPin) == HIGH) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Generic Switch Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + // Check Simulated Occupancy Sensor and set Matter Attribute + OccupancySensor.setOccupancy(simulatedHWOccupancySensor()); + + delay(50); +} diff --git a/libraries/Matter/examples/MatterOccupancySensor/ci.json b/libraries/Matter/examples/MatterOccupancySensor/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterOccupancySensor/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/MatterOnIdentify/MatterOnIdentify.ino b/libraries/Matter/examples/MatterOnIdentify/MatterOnIdentify.ino new file mode 100644 index 00000000000..b2e77900e95 --- /dev/null +++ b/libraries/Matter/examples/MatterOnIdentify/MatterOnIdentify.ino @@ -0,0 +1,164 @@ +// 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. + +/* + * This example is the smallest code that will create a Matter Device which can be + * commissioned and controlled from a Matter Environment APP. + * It controls a GPIO that could be attached to a LED for visualization. + * Additionally the ESP32 will send debug messages indicating the Matter activity. + * Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages. + * + * This example is a simple Matter On/Off Light that can be controlled by a Matter Controller. + * It demonstrates how to use On Identify callback when the Identify Cluster is called. + * The Matter user APP can be used to request the device to identify itself by blinking the LED. + */ + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Single On/Off Light Endpoint - at least one per node +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 + +// Light GPIO that can be controlled by Matter APP +#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 +#endif + +// set your board USER BUTTON pin here - decommissioning button +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control - decommision the Matter Node +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Identify Flag and blink time - Blink the LED +const uint8_t identifyLedPin = ledPin; // uses the same LED as the Light - change if needed +volatile bool identifyFlag = false; // Flag to start the Blink when in Identify state +bool identifyBlink = false; // Blink state when in Identify state + +// Matter Protocol Endpoint (On/OFF Light) Callback +bool onOffLightCallback(bool state) { + digitalWrite(ledPin, state ? HIGH : LOW); + // This callback must return the success state to Matter core + return true; +} + +// Identification shall be done by Blink in Red or just the GPIO when no LED_BUILTIN is not defined +bool onIdentifyLightCallback(bool identifyIsActive) { + Serial.printf("Identify Cluster is %s\r\n", identifyIsActive ? "Active" : "Inactive"); + if (identifyIsActive) { + // Start Blinking the light in loop() + identifyFlag = true; + identifyBlink = !OnOffLight; // Start with the inverted light state + } else { + // Stop Blinking and restore the light to the its last state + identifyFlag = false; + // force returning to the original state by toggling the light twice + OnOffLight.toggle(); + OnOffLight.toggle(); + } + return true; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + // Initialize the LED GPIO + pinMode(ledPin, OUTPUT); + + Serial.begin(115200); + + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); + + // Initialize at least one Matter EndPoint + OnOffLight.begin(); + + // On Identify Callback - Blink the LED + OnOffLight.onIdentify(onIdentifyLightCallback); + + // Associate a callback to the Matter Controller + OnOffLight.onChange(onOffLightCallback); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + // Check Matter Accessory 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 Occupancy Sensor 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."); + } +} + +void loop() { + // check if the Light is in identify state and blink it every 500ms (delay loop time) + if (identifyFlag) { +#ifdef LED_BUILTIN + uint8_t brightness = 32 * identifyBlink; + rgbLedWrite(identifyLedPin, brightness, 0, 0); +#else + digitalWrite(identifyLedPin, identifyBlink ? HIGH : LOW); +#endif + identifyBlink = !identifyBlink; + } + + // 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. + } + + if (digitalRead(buttonPin) == HIGH && button_state) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + delay(500); // works as a debounce for the button and also for the LED blink +} diff --git a/libraries/Matter/examples/MatterOnIdentify/ci.json b/libraries/Matter/examples/MatterOnIdentify/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterOnIdentify/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..5faa0a385b0 --- /dev/null +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.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. + +// Matter Manager +#include +#include +#include + +// 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 + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +MatterOnOffLight OnOffLight; + +// it will keep last OnOff state stored, using Preferences +Preferences matterPref; +const char *onOffPrefKey = "OnOff"; + +// 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 = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission + +// 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 + matterPref.putBool(onOffPrefKey, state); + // This callback must return the success state to Matter core + return true; +} + +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); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // 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 + matterPref.begin("MatterPrefs", false); + bool lastOnOffState = matterPref.getBool(onOffPrefKey, true); + OnOffLight.begin(lastOnOffState); + OnOffLight.onChange(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"); + OnOffLight.updateAccessory(); // configure the Light based on initial state + } +} + +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"); + OnOffLight.updateAccessory(); // 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 + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + OnOffLight.setOnOff(false); // turn the light off + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } +} 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/examples/MatterOnOffPlugin/MatterOnOffPlugin.ino b/libraries/Matter/examples/MatterOnOffPlugin/MatterOnOffPlugin.ino new file mode 100644 index 00000000000..d14e2189ec1 --- /dev/null +++ b/libraries/Matter/examples/MatterOnOffPlugin/MatterOnOffPlugin.ino @@ -0,0 +1,142 @@ +// 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. + +// Matter Manager +#include +#include +#include + +// List of Matter Endpoints for this Node +// On/Off Plugin Endpoint +MatterOnOffPlugin OnOffPlugin; + +// 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 + +// it will keep last OnOff state stored, using Preferences +Preferences matterPref; +const char *onOffPrefKey = "OnOff"; + +// set your board Power Relay pin here - this example uses the built-in LED for easy visualization +#ifdef LED_BUILTIN +const uint8_t onoffPin = LED_BUILTIN; +#else +const uint8_t onoffPin = 2; // Set your pin here - usually a power relay +#warning "Do not forget to set the Power Relay pin" +#endif + +// board USER BUTTON pin necessary for Decommissioning +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Matter Protocol Endpoint Callback +bool setPluginOnOff(bool state) { + Serial.printf("User Callback :: New Plugin State = %s\r\n", state ? "ON" : "OFF"); + if (state) { + digitalWrite(onoffPin, HIGH); + } else { + digitalWrite(onoffPin, LOW); + } + // store last OnOff state for when the Plugin is restarted / power goes off + matterPref.putBool(onOffPrefKey, state); + // This callback must return the success state to Matter core + return true; +} + +void setup() { + // Initialize the USER BUTTON + pinMode(buttonPin, INPUT_PULLUP); + // Initialize the Power Relay (plugin) GPIO + pinMode(onoffPin, OUTPUT); + + Serial.begin(115200); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + 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 + matterPref.begin("MatterPrefs", false); + bool lastOnOffState = matterPref.getBool(onOffPrefKey, false); + OnOffPlugin.begin(lastOnOffState); + OnOffPlugin.onChange(setPluginOnOff); + + // 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", OnOffPlugin.getOnOff() ? "ON" : "OFF"); + OnOffPlugin.updateAccessory(); // configure the Plugin based on initial state + } +} + +void loop() { + // Check Matter Plugin 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 Plugin 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", OnOffPlugin.getOnOff() ? "ON" : "OFF"); + OnOffPlugin.updateAccessory(); // configure the Plugin based on initial state + Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); + } + + // 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 to decommission the Matter Node + if (button_state && digitalRead(buttonPin) == HIGH) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Plugin Matter Accessory. It shall be commissioned again."); + OnOffPlugin.setOnOff(false); // turn the plugin off + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } +} diff --git a/libraries/Matter/examples/MatterOnOffPlugin/ci.json b/libraries/Matter/examples/MatterOnOffPlugin/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterOnOffPlugin/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/MatterPressureSensor/MatterPressureSensor.ino b/libraries/Matter/examples/MatterPressureSensor/MatterPressureSensor.ino new file mode 100644 index 00000000000..394a217b87a --- /dev/null +++ b/libraries/Matter/examples/MatterPressureSensor/MatterPressureSensor.ino @@ -0,0 +1,131 @@ +// 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. + +/* + * This example is an example code that will create a Matter Device which can be + * commissioned and controlled from a Matter Environment APP. + * Additionally the ESP32 will send debug messages indicating the Matter activity. + * Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages. + */ + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Matter Pressure Sensor Endpoint +MatterPressureSensor SimulatedPressureSensor; + +// 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 + +// set your board USER BUTTON pin here - decommissioning button +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control - decommision the Matter Node +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Simulate a pressure sensor - add your preferred pressure sensor library code here +float getSimulatedPressure() { + // The Endpoint implementation keeps an uint16_t as internal value information, + // which stores data in hPa (pressure measurement unit) + static float simulatedPressureHWSensor = 950; + + // it will increase from 950 to 1100 hPa in steps of 10 hPa to simulate a pressure sensor + simulatedPressureHWSensor = simulatedPressureHWSensor + 10; + if (simulatedPressureHWSensor > 1100) { + simulatedPressureHWSensor = 950; + } + + return simulatedPressureHWSensor; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); + + // set initial pressure sensor measurement + // Simulated Sensor - it shall initially print 900hPa and then move to the 950 to 1100 hPa as pressure range + SimulatedPressureSensor.begin(900.00); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + // Check Matter Accessory 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 Pressure Sensor 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."); + } +} + +void loop() { + static uint32_t timeCounter = 0; + + // Print the current pressure value every 5s + if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s + // Print the current pressure value + Serial.printf("Current Pressure is %.02fhPa\r\n", SimulatedPressureSensor.getPressure()); + // Update Pressure from the (Simulated) Hardware Sensor + // Matter APP shall display the updated pressure percent + SimulatedPressureSensor.setPressure(getSimulatedPressure()); + } + + // 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. + } + + if (digitalRead(buttonPin) == HIGH && button_state) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + // Factory reset is triggered if the button is pressed longer than 10 seconds + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + } + + delay(500); +} diff --git a/libraries/Matter/examples/MatterPressureSensor/ci.json b/libraries/Matter/examples/MatterPressureSensor/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterPressureSensor/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/MatterSmartButon/MatterSmartButon.ino b/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino new file mode 100644 index 00000000000..f8da970595d --- /dev/null +++ b/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.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. + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Generic Switch Endpoint - works as a smart button with a single click +MatterGenericSwitch SmartButton; + +// 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 + +// set your board USER BUTTON pin here +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission + +void setup() { + // Initialize the USER BUTTON (Boot button) GPIO that will act as a smart button or to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + + // 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 the Matter EndPoint + SmartButton.begin(); + + // 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."); + } +} + +void loop() { + // Check Matter Accessory 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 Generic Switch 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."); + } + + // A builtin button is used to trigger a command to the Matter Controller + // 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 smart button 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 + // builtin button is released - send a click event to the Matter Controller + Serial.println("User button released. Sending Click to the Matter Controller!"); + // Matter Controller will receive an event and, if programmed, it will trigger an action + SmartButton.click(); + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Generic Switch Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } +} diff --git a/libraries/Matter/examples/MatterSmartButon/ci.json b/libraries/Matter/examples/MatterSmartButon/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterSmartButon/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/MatterTemperatureLight/MatterTemperatureLight.ino b/libraries/Matter/examples/MatterTemperatureLight/MatterTemperatureLight.ino new file mode 100644 index 00000000000..b814ba89704 --- /dev/null +++ b/libraries/Matter/examples/MatterTemperatureLight/MatterTemperatureLight.ino @@ -0,0 +1,192 @@ +// 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. + +// Matter Manager +#include +#include +#include + +// List of Matter Endpoints for this Node +// Color Temperature CW/WW Light Endpoint +MatterColorTemperatureLight CW_WW_Light; + +// 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 + +// it will keep last OnOff & Brightness state stored, using Preferences +Preferences matterPref; +const char *onOffPrefKey = "OnOff"; +const char *brightnessPrefKey = "Brightness"; +const char *temperaturePrefKey = "Temperature"; + +// set your board RGB LED pin here +#ifdef RGB_BUILTIN +const uint8_t ledPin = RGB_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 RGB LED pin" +#endif + +// set your board USER BUTTON pin here +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Set the RGB LED Light based on the current state of the Color Temperature Light +bool setLightState(bool state, uint8_t brightness, uint16_t temperature_Mireds) { + + if (state) { +#ifdef RGB_BUILTIN + espRgbColor_t rgb_ct = espCTToRgbColor(temperature_Mireds); + // simple intensity correction + float brightnessPercent = (float)brightness / MatterColorTemperatureLight::MAX_BRIGHTNESS; + rgb_ct.r = brightnessPercent * rgb_ct.r; + rgb_ct.g = brightnessPercent * rgb_ct.g; + rgb_ct.b = brightnessPercent * rgb_ct.b; + // set the RGB LED + rgbLedWrite(ledPin, rgb_ct.r, rgb_ct.g, rgb_ct.b); +#else + // No Color RGB LED, just use the brightness to control the LED + analogWrite(ledPin, brightness); +#endif + } else { + digitalWrite(ledPin, LOW); + } + // store last Brightness and OnOff state for when the Light is restarted / power goes off + matterPref.putUChar(brightnessPrefKey, brightness); + matterPref.putBool(onOffPrefKey, state); + matterPref.putUShort(temperaturePrefKey, temperature_Mireds); + // This callback must return the success state to Matter core + return true; +} + +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); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // 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 + matterPref.begin("MatterPrefs", false); + // default OnOff state is ON if not stored before + bool lastOnOffState = matterPref.getBool(onOffPrefKey, true); + // default brightness ~= 6% (15/255) + uint8_t lastBrightness = matterPref.getUChar(brightnessPrefKey, 15); + // default temperature ~= 454 Mireds (Warm White) + uint16_t lastTemperature = matterPref.getUShort(temperaturePrefKey, WARM_WHITE_COLOR_TEMPERATURE.ctMireds); + CW_WW_Light.begin(lastOnOffState, lastBrightness, lastTemperature); + // set the callback function to handle the Light state change + CW_WW_Light.onChange(setLightState); + + // lambda functions are used to set the attribute change callbacks + CW_WW_Light.onChangeOnOff([](bool state) { + Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF"); + return true; + }); + CW_WW_Light.onChangeBrightness([](uint8_t level) { + Serial.printf("Light Brightness changed to %d\r\n", level); + return true; + }); + CW_WW_Light.onChangeColorTemperature([](uint16_t temperature) { + Serial.printf("Light Color Temperature changed to %d\r\n", temperature); + return true; + }); + + // 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 | brightness: %d | Color Temperature: %d mireds \r\n", CW_WW_Light ? "ON" : "OFF", CW_WW_Light.getBrightness(), + CW_WW_Light.getColorTemperature() + ); + // configure the Light based on initial on-off state and brightness + CW_WW_Light.updateAccessory(); + } +} + +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 | brightness: %d | Color Temperature: %d mireds \r\n", CW_WW_Light ? "ON" : "OFF", CW_WW_Light.getBrightness(), + CW_WW_Light.getColorTemperature() + ); + // configure the Light based on initial on-off state and brightness + CW_WW_Light.updateAccessory(); + 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!"); + CW_WW_Light.toggle(); // Matter Controller also can see the change + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + CW_WW_Light = false; // turn the light off + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } +} diff --git a/libraries/Matter/examples/MatterTemperatureLight/ci.json b/libraries/Matter/examples/MatterTemperatureLight/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterTemperatureLight/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/MatterTemperatureSensor/MatterTemperatureSensor.ino b/libraries/Matter/examples/MatterTemperatureSensor/MatterTemperatureSensor.ino new file mode 100644 index 00000000000..e8513f12aaa --- /dev/null +++ b/libraries/Matter/examples/MatterTemperatureSensor/MatterTemperatureSensor.ino @@ -0,0 +1,131 @@ +// 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. + +/* + * This example is an example code that will create a Matter Device which can be + * commissioned and controlled from a Matter Environment APP. + * Additionally the ESP32 will send debug messages indicating the Matter activity. + * Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages. + */ + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Matter Temperature Sensor Endpoint +MatterTemperatureSensor SimulatedTemperatureSensor; + +// 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 + +// set your board USER BUTTON pin here - decommissioning button +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control - decommision the Matter Node +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Simulate a temperature sensor - add your preferred temperature sensor library code here +float getSimulatedTemperature() { + // The Endpoint implementation keeps an int16_t as internal value information, + // which stores data in 1/100th of any temperature unit + static float simulatedTempHWSensor = -10.0; + + // it will increase from -10C to 10C in 0.5C steps to simulate a temperature sensor + simulatedTempHWSensor = simulatedTempHWSensor + 0.5; + if (simulatedTempHWSensor > 10) { + simulatedTempHWSensor = -10; + } + + return simulatedTempHWSensor; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); + + // set initial temperature sensor measurement + // Simulated Sensor - it shall initially print -25 degrees and then move to the -10 to 10 range + SimulatedTemperatureSensor.begin(-25.00); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + // Check Matter Accessory 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 Temperature Sensor 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."); + } +} + +void loop() { + static uint32_t timeCounter = 0; + + // Print the current temperature value every 5s + if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s + // Print the current temperature value + Serial.printf("Current Temperature is %.02f \r\n", SimulatedTemperatureSensor.getTemperature()); + // Update Temperature from the (Simulated) Hardware Sensor + // Matter APP shall display the updated temperature percent + SimulatedTemperatureSensor.setTemperature(getSimulatedTemperature()); + } + + // 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. + } + + if (digitalRead(buttonPin) == HIGH && button_state) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + delay(500); +} diff --git a/libraries/Matter/examples/MatterTemperatureSensor/ci.json b/libraries/Matter/examples/MatterTemperatureSensor/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterTemperatureSensor/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/WiFiProvWithinMatter/WiFiProvWithinMatter.ino b/libraries/Matter/examples/WiFiProvWithinMatter/WiFiProvWithinMatter.ino new file mode 100644 index 00000000000..3434217624d --- /dev/null +++ b/libraries/Matter/examples/WiFiProvWithinMatter/WiFiProvWithinMatter.ino @@ -0,0 +1,152 @@ +/* + Please read README.md file in this folder, or on the web: + https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFiProv/examples/WiFiProv + + Note: This sketch takes up a lot of space for the app and may not be able to flash with default setting on some chips. + If you see Error like this: "Sketch too big" + In Arduino IDE go to: Tools > Partition scheme > chose anything that has more than 1.4MB APP + - for example "No OTA (2MB APP/2MB SPIFFS)" + + This example demonstrates that it is possible to provision WiFi using BLE or Software AP using + the ESP BLE Prov APP or ESP SoftAP Provisioning APP from Android Play or/and iOS APP Store + + Once the WiFi is provisioned, Matter will start its process as usual. + + This same Example could be used for any other WiFi Provisioning method. +*/ + +// Matter Manager +#include +#include +#include + +#if !CONFIG_BLUEDROID_ENABLED +#define USE_SOFT_AP // ESP32-S2 has no BLE, therefore, it shall use SoftAP Provisioning +#endif +//#define USE_SOFT_AP // Uncomment if you want to enforce using the Soft AP method instead of BLE + +const char *pop = "abcd1234"; // Proof of possession - otherwise called a PIN - string provided by the device, entered by the user in the phone app +const char *service_name = "PROV_123"; // Name of your device (the Espressif apps expects by default device name starting with "Prov_") +const char *service_key = NULL; // Password used for SofAP method (NULL = no password needed) +bool reset_provisioned = true; // When true the library will automatically delete previously provisioned data. + +// List of Matter Endpoints for this Node +// Single On/Off Light Endpoint - at least one per node +MatterOnOffLight OnOffLight; + +// Light GPIO that can be controlled by Matter APP +#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 +#endif + +// set your board USER BUTTON pin here - decommissioning button +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control - decommision the Matter Node +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Matter Protocol Endpoint (On/OFF Light) Callback +bool matterCB(bool state) { + digitalWrite(ledPin, state ? HIGH : LOW); + // This callback must return the success state to Matter core + return true; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + // Initialize the LED GPIO + pinMode(ledPin, OUTPUT); + + WiFi.begin(); // no SSID/PWD - get it from the Provisioning APP or from NVS (last successful connection) + + // BLE Provisioning using the ESP SoftAP Prov works fine for any BLE SoC, including ESP32, ESP32S3 and ESP32C3. +#if CONFIG_BLUEDROID_ENABLED && !defined(USE_SOFT_AP) + Serial.println("Begin Provisioning using BLE"); + // Sample uuid that user can pass during provisioning using BLE + uint8_t uuid[16] = {0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf, 0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02}; + WiFiProv.beginProvision( + NETWORK_PROV_SCHEME_BLE, NETWORK_PROV_SCHEME_HANDLER_FREE_BLE, NETWORK_PROV_SECURITY_1, pop, service_name, service_key, uuid, reset_provisioned + ); + Serial.println("You may use this BLE QRCode:"); + WiFiProv.printQR(service_name, pop, "ble"); +#else + Serial.println("Begin Provisioning using Soft AP"); + WiFiProv.beginProvision(NETWORK_PROV_SCHEME_SOFTAP, NETWORK_PROV_SCHEME_HANDLER_NONE, NETWORK_PROV_SECURITY_1, pop, service_name, service_key); + Serial.println("You may use this WiFi QRCode:"); + WiFiProv.printQR(service_name, pop, "softap"); +#endif + + // Wait for WiFi connection + uint32_t counter = 0; + while (WiFi.status() != WL_CONNECTED) { + // resets the device after 10 minutes + if (counter > 2 * 60 * 10) { + Serial.println("\r\n================================================"); + Serial.println("Already 10 minutes past. The device will reboot."); + Serial.println("================================================\r\n"); + Serial.flush(); // wait until the Serial has sent the whole message. + ESP.restart(); + } + // WiFi searching feedback + Serial.print("."); + delay(500); + // adds a new line every 30 seconds + counter++; + if (!(counter % 60)) { + Serial.println(); + } + } + + // WiFi shall be connected by now + Serial.println(); + + // Initialize at least one Matter EndPoint + OnOffLight.begin(); + + // Associate a callback to the Matter Controller + OnOffLight.onChange(matterCB); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + while (!Matter.isDeviceCommissioned()) { + 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()); + Serial.println(); + // waits 30 seconds for Matter Commissioning, keeping it blocked until done + delay(30000); + } +} + +void loop() { + // 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. + } + + if (digitalRead(buttonPin) == HIGH && button_state) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + delay(500); +} diff --git a/libraries/Matter/examples/WiFiProvWithinMatter/ci.json b/libraries/Matter/examples/WiFiProvWithinMatter/ci.json new file mode 100644 index 00000000000..0665800b12b --- /dev/null +++ b/libraries/Matter/examples/WiFiProvWithinMatter/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..3f40e598ada --- /dev/null +++ b/libraries/Matter/keywords.txt @@ -0,0 +1,106 @@ +####################################### +# Syntax Coloring Map For Matter +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Matter KEYWORD1 +ArduinoMatter KEYWORD1 +MatterGenericSwitch KEYWORD1 +MatterOnOffLight KEYWORD1 +MatterDimmableLight KEYWORD1 +MatterColorTemperatureLight KEYWORD1 +MatterColorLight KEYWORD1 +MatterEnhancedColorLight KEYWORD1 +MatterEndPoint KEYWORD1 +MatterFan KEYWORD1 +FanMode_t KEYWORD1 +FanModeSequence_t KEYWORD1 +MatterTemperatureSensor KEYWORD1 +MatterHumiditySensor KEYWORD1 +MatterContactSensor KEYWORD1 +MatterPressureSensor KEYWORD1 +MatterOccupancySensor KEYWORD1 +MatterOnOffPlugin KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +getManualPairingCode KEYWORD2 +getOnboardingQRCodeUrl KEYWORD2 +isDeviceCommissioned KEYWORD2 +isWiFiConnected KEYWORD2 +isThreadConnected KEYWORD2 +isDeviceConnected KEYWORD2 +decommission KEYWORD2 +attributeChangeCB KEYWORD2 +setOnOff KEYWORD2 +getOnOff KEYWORD2 +toggle KEYWORD2 +setBrightness KEYWORD2 +getBrightness KEYWORD2 +setColorTemperature KEYWORD2 +getColorTemperature KEYWORD2 +setColorRGB KEYWORD2 +getColorRGB KEYWORD2 +setColorHSV KEYWORD2 +getColorHSV KEYWORD2 +updateAccessory KEYWORD2 +onChange KEYWORD2 +onChangeOnOff KEYWORD2 +onChangeBrightness KEYWORD2 +onChangeColorTemperature KEYWORD2 +onChangeColorHSV KEYWORD2 +click KEYWORD2 +getAttribute KEYWORD2 +getAttributeVal KEYWORD2 +setAttributeVal KEYWORD2 +updateAttributeVal KEYWORD2 +getFanModeString KEYWORD2 +setSpeedPercent KEYWORD2 +getSpeedPercent KEYWORD2 +setMode KEYWORD2 +getMode KEYWORD2 +onChangeMode KEYWORD2 +onChangeSpeedPercent KEYWORD2 +setTemperature KEYWORD2 +getTemperature KEYWORD2 +setHumidity KEYWORD2 +getHumidity KEYWORD2 +setContact KEYWORD2 +getContact KEYWORD2 +setPressure KEYWORD2 +getPressure KEYWORD2 +setOccupancy KEYWORD2 +getOccupancy KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +MAX_BRIGHTNESS LITERAL1 +MAX_COLOR_TEMPERATURE LITERAL1 +MIN_COLOR_TEMPERATURE LITERAL1 +ATTR_SET LITERAL1 +ATTR_UPDATE LITERAL1 +MAX_SPEED LITERAL1 +MIN_SPEED LITERAL1 +OFF_SPEED LITERAL1 +FAN_MODE_OFF LITERAL1 +FAN_MODE_LOW LITERAL1 +FAN_MODE_MEDIUM LITERAL1 +FAN_MODE_HIGH LITERAL1 +FAN_MODE_ON LITERAL1 +FAN_MODE_AUTO LITERAL1 +FAN_MODE_SMART LITERAL1 +FAN_MODE_SEQ_OFF_LOW_MED_HIGH LITERAL1 +FAN_MODE_SEQ_OFF_LOW_HIGH LITERAL1 +FAN_MODE_SEQ_OFF_LOW_MED_HIGH_AUTO LITERAL1 +FAN_MODE_SEQ_OFF_LOW_HIGH_AUTO LITERAL1 +FAN_MODE_SEQ_OFF_HIGH_AUTO LITERAL1 +FAN_MODE_SEQ_OFF_HIGH 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..af7c4c8657e --- /dev/null +++ b/libraries/Matter/src/Matter.cpp @@ -0,0 +1,191 @@ +// 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 +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +using namespace esp_matter; +using namespace esp_matter::attribute; +using namespace esp_matter::endpoint; +using namespace esp_matter::identification; +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; + +// 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 +) { + log_d("Attribute update callback: type: %u, endpoint: %u, cluster: %u, attribute: %u, val: %u", type, endpoint_id, cluster_id, attribute_id, val->val.u32); + 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_v("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_v("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_v("Attribute update callback: READ"); + break; + case WRITE: // Callback for writing the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. + log_v("Attribute update callback: WRITE"); + break; + default: log_v("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_d("Identification callback to endpoint %d: type: %u, effect: %u, variant: %u", endpoint_id, type, effect_id, effect_variant); + esp_err_t err = ESP_OK; + MatterEndPoint *ep = (MatterEndPoint *)priv_data; // endpoint pointer to base class + // Identify the endpoint sending a counter to the application + bool identifyIsActive = false; + + if (type == identification::callback_type_t::START) { + log_v("Identification callback: START"); + identifyIsActive = true; + } else if (type == identification::callback_type_t::EFFECT) { + log_v("Identification callback: EFFECT"); + } else if (type == identification::callback_type_t::STOP) { + identifyIsActive = false; + log_v("Identification callback: STOP"); + } + if (ep != NULL) { + err = ep->endpointIdentifyCB(endpoint_id, identifyIsActive) ? ESP_OK : ESP_FAIL; + } + + return err; +} + +// 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_e("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..7fcab363f11 --- /dev/null +++ b/libraries/Matter/src/Matter.h @@ -0,0 +1,80 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 MatterGenericSwitch; + friend class MatterOnOffLight; + friend class MatterDimmableLight; + friend class MatterColorTemperatureLight; + friend class MatterColorLight; + friend class MatterEnhancedColorLight; + friend class MatterFan; + friend class MatterTemperatureSensor; + friend class MatterHumiditySensor; + friend class MatterContactSensor; + friend class MatterPressureSensor; + friend class MatterOccupancySensor; + friend class MatterOnOffPlugin; + +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..6f99aa7cd33 --- /dev/null +++ b/libraries/Matter/src/MatterEndPoint.h @@ -0,0 +1,122 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +using namespace esp_matter; + +// Matter Endpoint Base Class. Controls the endpoint ID and allows the child class to overwrite attribute change call +class MatterEndPoint { +public: + enum attrOperation_t { + ATTR_SET = false, + ATTR_UPDATE = true + }; + + uint16_t getEndPointId() { + return endpoint_id; + } + + void setEndPointId(uint16_t ep) { + endpoint_id = ep; + } + + // helper functions for attribute manipulation + attribute_t *getAttribute(uint32_t cluster_id, uint32_t attribute_id) { + if (endpoint_id == 0) { + log_e("Endpoint ID is not set"); + return NULL; + } + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + if (endpoint == NULL) { + log_e("Endpoint [%d] not found", endpoint_id); + return NULL; + } + cluster_t *cluster = cluster::get(endpoint, cluster_id); + if (cluster == NULL) { + log_e("Cluster [%d] not found", cluster_id); + return NULL; + } + attribute_t *attribute = attribute::get(cluster, attribute_id); + if (attribute == NULL) { + log_e("Attribute [%d] not found", attribute_id); + return NULL; + } + return attribute; + } + + // get the value of an attribute from its cluster id and attribute it + bool getAttributeVal(uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *attrVal) { + attribute_t *attribute = getAttribute(cluster_id, attribute_id); + if (attribute == NULL) { + return false; + } + if (attribute::get_val(attribute, attrVal) == ESP_OK) { + log_v("GET_VAL Success for cluster %d, attribute %d with value %d", cluster_id, attribute_id, attrVal->val.u32); + return true; + } + log_e("GET_VAL FAILED! for cluster %d, attribute %d with value %d", cluster_id, attribute_id, attrVal->val.u32); + return false; + } + + // set the value of an attribute from its cluster id and attribute it + bool setAttributeVal(uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *attrVal) { + attribute_t *attribute = getAttribute(cluster_id, attribute_id); + if (attribute == NULL) { + return false; + } + if (attribute::set_val(attribute, attrVal) == ESP_OK) { + log_v("SET_VAL Success for cluster %d, attribute %d with value %d", cluster_id, attribute_id, attrVal->val.u32); + return true; + } + log_e("SET_VAL FAILED! for cluster %d, attribute %d with value %d", cluster_id, attribute_id, attrVal->val.u32); + return false; + } + + // update the value of an attribute from its cluster id and attribute it + bool updateAttributeVal(uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *attrVal) { + if (attribute::update(endpoint_id, cluster_id, attribute_id, attrVal) == ESP_OK) { + log_v("Update Success for cluster %d, attribute %d with value %d", cluster_id, attribute_id, attrVal->val.u32); + return true; + } + log_e("Update FAILED! for cluster %d, attribute %d with value %d", cluster_id, attribute_id, attrVal->val.u32); + return false; + } + + // this function is called by Matter internal event processor. It could be overwritten by the application, if necessary. + virtual bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) = 0; + + // This callback is invoked when clients interact with the Identify Cluster of an specific endpoint. + bool endpointIdentifyCB(uint16_t endpoint_id, bool identifyIsEnabled) { + if (_onEndPointIdentifyCB) { + return _onEndPointIdentifyCB(identifyIsEnabled); + } + return true; + } + // User callaback for the Identify Cluster functionality + using EndPointIdentifyCB = std::function; + void onIdentify(EndPointIdentifyCB onEndPointIdentifyCB) { + _onEndPointIdentifyCB = onEndPointIdentifyCB; + } + +protected: + uint16_t endpoint_id = 0; + EndPointIdentifyCB _onEndPointIdentifyCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp b/libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp new file mode 100644 index 00000000000..eaaf0bf2ffe --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp @@ -0,0 +1,312 @@ +// 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 +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +// endpoint for color light device +namespace esp_matter { +using namespace cluster; +namespace endpoint { +namespace rgb_color_light { +typedef struct config { + cluster::descriptor::config_t descriptor; + cluster::identify::config_t identify; + cluster::groups::config_t groups; + cluster::scenes_management::config_t scenes_management; + cluster::on_off::config_t on_off; + cluster::level_control::config_t level_control; + cluster::color_control::config_t color_control; +} config_t; + +uint32_t get_device_type_id() { + return ESP_MATTER_EXTENDED_COLOR_LIGHT_DEVICE_TYPE_ID; +} + +uint8_t get_device_type_version() { + return ESP_MATTER_EXTENDED_COLOR_LIGHT_DEVICE_TYPE_VERSION; +} + +esp_err_t add(endpoint_t *endpoint, config_t *config) { + if (!endpoint) { + log_e("Endpoint cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + esp_err_t err = add_device_type(endpoint, get_device_type_id(), get_device_type_version()); + if (err != ESP_OK) { + log_e("Failed to add device type id:%" PRIu32 ",err: %d", get_device_type_id(), err); + return err; + } + + descriptor::create(endpoint, &(config->descriptor), CLUSTER_FLAG_SERVER); + cluster_t *identify_cluster = identify::create(endpoint, &(config->identify), CLUSTER_FLAG_SERVER); + identify::command::create_trigger_effect(identify_cluster); + groups::create(endpoint, &(config->groups), CLUSTER_FLAG_SERVER); + cluster_t *scenes_cluster = scenes_management::create(endpoint, &(config->scenes_management), CLUSTER_FLAG_SERVER); + scenes_management::command::create_copy_scene(scenes_cluster); + scenes_management::command::create_copy_scene_response(scenes_cluster); + + on_off::create(endpoint, &(config->on_off), CLUSTER_FLAG_SERVER, on_off::feature::lighting::get_id()); + level_control::create( + endpoint, &(config->level_control), CLUSTER_FLAG_SERVER, level_control::feature::on_off::get_id() | level_control::feature::lighting::get_id() + ); + color_control::create(endpoint, &(config->color_control), CLUSTER_FLAG_SERVER, color_control::feature::hue_saturation::get_id()); + return ESP_OK; +} + +endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data) { + endpoint_t *endpoint = endpoint::create(node, flags, priv_data); + add(endpoint, config); + return endpoint; +} +} // namespace rgb_color_light +} // namespace endpoint +} // namespace esp_matter + +bool MatterColorLight::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_e("Matter RGB Color Light device has not begun."); + return false; + } + + log_d( + "RGB Color Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u, type: %u", endpoint_id, cluster_id, attribute_id, val->val.u32, + val->type + ); + + if (endpoint_id == getEndPointId()) { + switch (cluster_id) { + case OnOff::Id: + if (attribute_id == OnOff::Attributes::OnOff::Id) { + log_d("RGB Color Light On/Off State changed to %d", val->val.b); + if (_onChangeOnOffCB != NULL) { + ret &= _onChangeOnOffCB(val->val.b); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(val->val.b, colorHSV); + } + if (ret == true) { + onOffState = val->val.b; + } + } + break; + case LevelControl::Id: + if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) { + log_d("RGB Color Light Brightness changed to %d", val->val.u8); + if (_onChangeColorCB != NULL) { + ret &= _onChangeColorCB({colorHSV.h, colorHSV.s, val->val.u8}); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(onOffState, {colorHSV.h, colorHSV.s, val->val.u8}); + } + if (ret == true) { + colorHSV.v = val->val.u8; + } + } + break; + case ColorControl::Id: + { + if (attribute_id != ColorControl::Attributes::CurrentHue::Id && attribute_id != ColorControl::Attributes::CurrentSaturation::Id) { + log_i("Color Control Attribute ID [%x] not processed.", attribute_id); + break; + } + espHsvColor_t hsvColor = {colorHSV.h, colorHSV.s, colorHSV.v}; + if (attribute_id == ColorControl::Attributes::CurrentHue::Id) { + log_d("RGB Light Hue changed to %d", val->val.u8); + hsvColor.h = val->val.u8; + } else { // attribute_id == ColorControl::Attributes::CurrentSaturation::Id) + log_d("RGB Light Saturation changed to %d", val->val.u8); + hsvColor.s = val->val.u8; + } + if (_onChangeColorCB != NULL) { + ret &= _onChangeColorCB(hsvColor); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(onOffState, hsvColor); + } + if (ret == true) { + colorHSV = {hsvColor.h, hsvColor.s, hsvColor.v}; + } + break; + } + } + } + return ret; +} + +MatterColorLight::MatterColorLight() {} + +MatterColorLight::~MatterColorLight() { + end(); +} + +bool MatterColorLight::begin(bool initialState, espHsvColor_t _colorHSV) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter RGB Color Light with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + rgb_color_light::config_t light_config; + light_config.on_off.on_off = initialState; + light_config.on_off.lighting.start_up_on_off = nullptr; + onOffState = initialState; + + light_config.level_control.current_level = _colorHSV.v; + light_config.level_control.lighting.start_up_current_level = nullptr; + + light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::kCurrentHueAndCurrentSaturation; + light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::kCurrentHueAndCurrentSaturation; + light_config.color_control.hue_saturation.current_hue = _colorHSV.h; + light_config.color_control.hue_saturation.current_saturation = _colorHSV.s; + colorHSV = {_colorHSV.h, _colorHSV.s, _colorHSV.v}; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = rgb_color_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create RGB Color light endpoint"); + return false; + } + + setEndPointId(endpoint::get_id(endpoint)); + log_i("RGB Color Light created with endpoint_id %d", getEndPointId()); + + /* Mark deferred persistence for some attributes that might be changed rapidly */ + cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id); + attribute_t *current_level_attribute = attribute::get(level_control_cluster, LevelControl::Attributes::CurrentLevel::Id); + attribute::set_deferred_persistence(current_level_attribute); + + started = true; + return true; +} + +void MatterColorLight::end() { + started = false; +} + +bool MatterColorLight::setOnOff(bool newState) { + if (!started) { + log_e("Matter RGB Color Light device has not begun."); + return false; + } + + // avoid processing if there was no change + if (onOffState == newState) { + return true; + } + + onOffState = 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 != onOffState) { + val.val.b = onOffState; + attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); + } + return true; +} + +void MatterColorLight::updateAccessory() { + if (_onChangeCB != NULL) { + _onChangeCB(onOffState, colorHSV); + } +} + +bool MatterColorLight::getOnOff() { + return onOffState; +} + +bool MatterColorLight::toggle() { + return setOnOff(!onOffState); +} + +bool MatterColorLight::setColorRGB(espRgbColor_t _rgbColor) { + return setColorHSV(espRgbColorToHsvColor(_rgbColor)); +} + +espRgbColor_t MatterColorLight::getColorRGB() { + return espHsvColorToRgbColor(colorHSV); +} + +bool MatterColorLight::setColorHSV(espHsvColor_t _hsvColor) { + + if (!started) { + log_w("Matter RGB Color Light device has not begun."); + return false; + } + + // avoid processing if there was no change + if (colorHSV.h == _hsvColor.h && colorHSV.s == _hsvColor.s && colorHSV.v == _hsvColor.v) { + return true; + } + + colorHSV = {_hsvColor.h, _hsvColor.s, _hsvColor.v}; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, ColorControl::Id); + // update hue + attribute_t *attribute = attribute::get(cluster, ColorControl::Attributes::CurrentHue::Id); + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + if (val.val.u8 != colorHSV.h) { + val.val.u8 = colorHSV.h; + attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::CurrentHue::Id, &val); + } + // update saturation + attribute = attribute::get(cluster, ColorControl::Attributes::CurrentSaturation::Id); + val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + if (val.val.u8 != colorHSV.s) { + val.val.u8 = colorHSV.s; + attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::CurrentSaturation::Id, &val); + } + // update value (brightness) + cluster = cluster::get(endpoint, LevelControl::Id); + attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id); + val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + if (val.val.u8 != colorHSV.v) { + val.val.u8 = colorHSV.v; + attribute::update(endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &val); + } + return true; +} + +espHsvColor_t MatterColorLight::getColorHSV() { + return colorHSV; +} + +MatterColorLight::operator bool() { + return getOnOff(); +} + +void MatterColorLight::operator=(bool newState) { + setOnOff(newState); +} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterColorLight.h b/libraries/Matter/src/MatterEndpoints/MatterColorLight.h new file mode 100644 index 00000000000..b896afa9b7a --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterColorLight.h @@ -0,0 +1,75 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterColorLight : public MatterEndPoint { +public: + MatterColorLight(); + ~MatterColorLight(); + // default initial state is off, color is red 12% intensity HSV(0, 254, 31) + virtual bool begin(bool initialState = false, espHsvColor_t colorHSV = {0, 254, 31}); + // this will just stop processing Light Matter events + void end(); + + bool setOnOff(bool newState); // returns true if successful + bool getOnOff(); // returns current light state + bool toggle(); // returns true if successful + + bool setColorRGB(espRgbColor_t rgbColor); // returns true if successful + espRgbColor_t getColorRGB(); // returns current RGB Color + bool setColorHSV(espHsvColor_t hsvColor); // returns true if successful + espHsvColor_t getColorHSV(); // returns current HSV Color + + // User Callback for whenever the Light On/Off state is changed by the Matter Controller + using EndPointOnOffCB = std::function; + void onChangeOnOff(EndPointOnOffCB onChangeCB) { + _onChangeOnOffCB = onChangeCB; + } + // User Callback for whenever the HSV Color value is changed by the Matter Controller + using EndPointRGBColorCB = std::function; + void onChangeColorHSV(EndPointRGBColorCB onChangeCB) { + _onChangeColorCB = onChangeCB; + } + + // User Callback for whenever any parameter is changed by the Matter Controller + using EndPointCB = std::function; + void onChange(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + + // used to update the state of the light using the current Matter Light internal state + // It is necessary to set a user callback function using onChange() to handle the physical light state + void updateAccessory(); + + operator bool(); // returns current on/off 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); + +protected: + bool started = false; + bool onOffState = false; // default initial state is off, but it can be changed by begin(bool) + espHsvColor_t colorHSV = {0}; // default initial color HSV is black, but it can be changed by begin(bool, espHsvColor_t) + EndPointOnOffCB _onChangeOnOffCB = NULL; + EndPointRGBColorCB _onChangeColorCB = NULL; + EndPointCB _onChangeCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp b/libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp new file mode 100644 index 00000000000..5ef69749bb1 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp @@ -0,0 +1,250 @@ +// 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 +#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 MatterColorTemperatureLight::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_e("Matter Temperature Light device has not begun."); + return false; + } + + log_d("Temperature Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + + if (endpoint_id == getEndPointId()) { + switch (cluster_id) { + case OnOff::Id: + if (attribute_id == OnOff::Attributes::OnOff::Id) { + log_d("Temperature Light On/Off State changed to %d", val->val.b); + if (_onChangeOnOffCB != NULL) { + ret &= _onChangeOnOffCB(val->val.b); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(val->val.b, brightnessLevel, colorTemperatureLevel); + } + if (ret == true) { + onOffState = val->val.b; + } + } + break; + case LevelControl::Id: + if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) { + log_d("Temperature Light Brightness changed to %d", val->val.u8); + if (_onChangeBrightnessCB != NULL) { + ret &= _onChangeBrightnessCB(val->val.u8); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(onOffState, val->val.u8, colorTemperatureLevel); + } + if (ret == true) { + brightnessLevel = val->val.u8; + } + } + break; + case ColorControl::Id: + if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) { + log_d("Temperature Light Temperature changed to %d", val->val.u16); + if (_onChangeTemperatureCB != NULL) { + ret &= _onChangeTemperatureCB(val->val.u16); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(onOffState, brightnessLevel, val->val.u16); + } + if (ret == true) { + colorTemperatureLevel = val->val.u16; + } + } + break; + } + } + return ret; +} + +MatterColorTemperatureLight::MatterColorTemperatureLight() {} + +MatterColorTemperatureLight::~MatterColorTemperatureLight() { + end(); +} + +bool MatterColorTemperatureLight::begin(bool initialState, uint8_t brightness, uint16_t ColorTemperature) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter Temperature Light with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + color_temperature_light::config_t light_config; + light_config.on_off.on_off = initialState; + light_config.on_off.lighting.start_up_on_off = nullptr; + onOffState = initialState; + + light_config.level_control.current_level = brightness; + light_config.level_control.lighting.start_up_current_level = nullptr; + brightnessLevel = brightness; + + light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature; + light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature; + light_config.color_control.color_temperature.color_temperature_mireds = ColorTemperature; + light_config.color_control.color_temperature.startup_color_temperature_mireds = nullptr; + colorTemperatureLevel = ColorTemperature; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = color_temperature_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Temperature Light endpoint"); + return false; + } + + setEndPointId(endpoint::get_id(endpoint)); + log_i("Temperature Light created with endpoint_id %d", getEndPointId()); + + /* Mark deferred persistence for some attributes that might be changed rapidly */ + cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id); + attribute_t *current_level_attribute = attribute::get(level_control_cluster, LevelControl::Attributes::CurrentLevel::Id); + attribute::set_deferred_persistence(current_level_attribute); + + cluster_t *color_control_cluster = cluster::get(endpoint, ColorControl::Id); + attribute_t *color_temp_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::ColorTemperatureMireds::Id); + attribute::set_deferred_persistence(color_temp_attribute); + + started = true; + return true; +} + +void MatterColorTemperatureLight::end() { + started = false; +} + +bool MatterColorTemperatureLight::setOnOff(bool newState) { + if (!started) { + log_e("Matter Temperature Light device has not begun."); + return false; + } + + // avoid processing if there was no change + if (onOffState == newState) { + return true; + } + + onOffState = 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 != onOffState) { + val.val.b = onOffState; + attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); + } + return true; +} + +void MatterColorTemperatureLight::updateAccessory() { + if (_onChangeCB != NULL) { + _onChangeCB(onOffState, brightnessLevel, colorTemperatureLevel); + } +} + +bool MatterColorTemperatureLight::getOnOff() { + return onOffState; +} + +bool MatterColorTemperatureLight::toggle() { + return setOnOff(!onOffState); +} + +bool MatterColorTemperatureLight::setBrightness(uint8_t newBrightness) { + if (!started) { + log_w("Matter Temperature Light device has not begun."); + return false; + } + + // avoid processing if there was no change + if (brightnessLevel == newBrightness) { + return true; + } + + brightnessLevel = newBrightness; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, LevelControl::Id); + attribute_t *attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id); + + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + + if (val.val.u8 != brightnessLevel) { + val.val.u8 = brightnessLevel; + attribute::update(endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &val); + } + return true; +} + +uint8_t MatterColorTemperatureLight::getBrightness() { + return brightnessLevel; +} + +bool MatterColorTemperatureLight::setColorTemperature(uint16_t newTemperature) { + if (!started) { + log_w("Matter Temperature Light device has not begun."); + return false; + } + + // avoid processing if there was no change + if (colorTemperatureLevel == newTemperature) { + return true; + } + + colorTemperatureLevel = newTemperature; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, ColorControl::Id); + attribute_t *attribute = attribute::get(cluster, ColorControl::Attributes::ColorTemperatureMireds::Id); + + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + + if (val.val.u16 != colorTemperatureLevel) { + val.val.u16 = colorTemperatureLevel; + attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::ColorTemperatureMireds::Id, &val); + } + return true; +} + +uint16_t MatterColorTemperatureLight::getColorTemperature() { + return colorTemperatureLevel; +} + +MatterColorTemperatureLight::operator bool() { + return getOnOff(); +} + +void MatterColorTemperatureLight::operator=(bool newState) { + setOnOff(newState); +} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.h b/libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.h new file mode 100644 index 00000000000..539bc386e92 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.h @@ -0,0 +1,89 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterColorTemperatureLight : public MatterEndPoint { +public: + static const uint8_t MAX_BRIGHTNESS = 255; + static const uint16_t MAX_COLOR_TEMPERATURE = 500; + static const uint16_t MIN_COLOR_TEMPERATURE = 100; + + MatterColorTemperatureLight(); + ~MatterColorTemperatureLight(); + // default initial state is off, brightness is 64 (25%) and temperature is 370 (Soft White) + virtual bool begin(bool initialState = false, uint8_t brightness = 64, uint16_t colorTemperature = 370); + // this will just stop processing Light Matter events + void end(); + + bool setOnOff(bool newState); // returns true if successful + bool getOnOff(); // returns current light state + bool toggle(); // returns true if successful + + bool setBrightness(uint8_t newBrightness); // returns true if successful + uint8_t getBrightness(); // returns current brightness + + bool setColorTemperature(uint16_t newTemperature); // returns true if successful + uint16_t getColorTemperature(); // returns current temperature + + // User Callback for whenever the Light On/Off state is changed by the Matter Controller + using EndPointOnOffCB = std::function; + void onChangeOnOff(EndPointOnOffCB onChangeCB) { + _onChangeOnOffCB = onChangeCB; + } + + // User Callback for whenever the Light brightness value [0..255] is changed by the Matter Controller + using EndPointBrightnessCB = std::function; + void onChangeBrightness(EndPointBrightnessCB onChangeCB) { + _onChangeBrightnessCB = onChangeCB; + } + + // User Callbqck for whenever the Light temperature value is changed by the Matter Controller + using EndPointTemperatureCB = std::function; + void onChangeColorTemperature(EndPointTemperatureCB onChangeCB) { + _onChangeTemperatureCB = onChangeCB; + } + + // User Callback for whenever any parameter is changed by the Matter Controller + using EndPointCB = std::function; + void onChange(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + + // used to update the state of the light using the current Matter Light internal state + // It is necessary to set a user callback function using onChange() to handle the physical light state + void updateAccessory(); + + operator bool(); // returns current on/off 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); + +protected: + bool started = false; + bool onOffState = false; // default initial state is off, but it can be changed by begin(bool) + uint8_t brightnessLevel = 0; // default initial brightness is 0, but it can be changed by begin(bool, uint8_t) + uint16_t colorTemperatureLevel = 0; // default initial color temperature is 0, but it can be changed by begin(bool, uint8_t, uint16_t) + EndPointOnOffCB _onChangeOnOffCB = NULL; + EndPointBrightnessCB _onChangeBrightnessCB = NULL; + EndPointTemperatureCB _onChangeTemperatureCB = NULL; + EndPointCB _onChangeCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterContactSensor.cpp b/libraries/Matter/src/MatterEndpoints/MatterContactSensor.cpp new file mode 100644 index 00000000000..17b0fe7a247 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterContactSensor.cpp @@ -0,0 +1,103 @@ +// 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 +#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 MatterContactSensor::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_e("Matter Contact Sensor device has not begun."); + return false; + } + + log_d("Contact Sensor Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + return ret; +} + +MatterContactSensor::MatterContactSensor() {} + +MatterContactSensor::~MatterContactSensor() { + end(); +} + +bool MatterContactSensor::begin(bool _contactState) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter Contact Sensor with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + contact_sensor::config_t contact_sensor_config; + contact_sensor_config.boolean_state.state_value = _contactState; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = contact_sensor::create(node::get(), &contact_sensor_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Contact Sensor endpoint"); + return false; + } + contactState = _contactState; + setEndPointId(endpoint::get_id(endpoint)); + log_i("Contact Sensor created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterContactSensor::end() { + started = false; +} + +bool MatterContactSensor::setContact(bool _contactState) { + if (!started) { + log_e("Matter Contact Sensor device has not begun."); + return false; + } + + // avoid processing if there was no change + if (contactState == _contactState) { + return true; + } + + esp_matter_attr_val_t contactVal = esp_matter_invalid(NULL); + + if (!getAttributeVal(BooleanState::Id, BooleanState::Attributes::StateValue::Id, &contactVal)) { + log_e("Failed to get Contact Sensor Attribute."); + return false; + } + if (contactVal.val.u8 != _contactState) { + contactVal.val.u8 = _contactState; + bool ret; + ret = updateAttributeVal(BooleanState::Id, BooleanState::Attributes::StateValue::Id, &contactVal); + if (!ret) { + log_e("Failed to update Contact Sensor Attribute."); + return false; + } + contactState = _contactState; + } + log_v("Contact Sensor set to %s", _contactState ? "Closed" : "Open"); + + return true; +} + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterContactSensor.h b/libraries/Matter/src/MatterEndpoints/MatterContactSensor.h new file mode 100644 index 00000000000..257da785e53 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterContactSensor.h @@ -0,0 +1,54 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterContactSensor : public MatterEndPoint { +public: + MatterContactSensor(); + ~MatterContactSensor(); + // begin Matter Contact Sensor endpoint with initial contact state + bool begin(bool _contactState = false); + // this will just stop processing Contact Sensor Matter events + void end(); + + // set the contact state + bool setContact(bool _contactState); + // returns the contact state + bool getContact() { + return contactState; + } + + // bool conversion operator + void operator=(bool _contactState) { + setContact(_contactState); + } + // bool conversion operator + operator bool() { + return getContact(); + } + + // 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); + +protected: + bool started = false; + bool contactState = false; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp b/libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp new file mode 100644 index 00000000000..9f6f872ca3e --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp @@ -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. + +#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 MatterDimmableLight::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_e("Matter DimmableLight device has not begun."); + return false; + } + + log_d("Dimmable Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + + if (endpoint_id == getEndPointId()) { + switch (cluster_id) { + case OnOff::Id: + if (attribute_id == OnOff::Attributes::OnOff::Id) { + log_d("DimmableLight On/Off State changed to %d", val->val.b); + if (_onChangeOnOffCB != NULL) { + ret &= _onChangeOnOffCB(val->val.b); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(val->val.b, brightnessLevel); + } + if (ret == true) { + onOffState = val->val.b; + } + } + break; + case LevelControl::Id: + if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) { + log_d("DimmableLight Brightness changed to %d", val->val.u8); + if (_onChangeBrightnessCB != NULL) { + ret &= _onChangeBrightnessCB(val->val.u8); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(onOffState, val->val.u8); + } + if (ret == true) { + brightnessLevel = val->val.u8; + } + } + break; + } + } + return ret; +} + +MatterDimmableLight::MatterDimmableLight() {} + +MatterDimmableLight::~MatterDimmableLight() { + end(); +} + +bool MatterDimmableLight::begin(bool initialState, uint8_t brightness) { + ArduinoMatter::_init(); + if (getEndPointId() != 0) { + log_e("Matter Dimmable Light with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + dimmable_light::config_t light_config; + light_config.on_off.on_off = initialState; + light_config.on_off.lighting.start_up_on_off = nullptr; + onOffState = initialState; + + light_config.level_control.current_level = brightness; + light_config.level_control.lighting.start_up_current_level = nullptr; + brightnessLevel = brightness; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = dimmable_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create dimmable light endpoint"); + return false; + } + + setEndPointId(endpoint::get_id(endpoint)); + log_i("Dimmable Light created with endpoint_id %d", getEndPointId()); + + /* Mark deferred persistence for some attributes that might be changed rapidly */ + cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id); + attribute_t *current_level_attribute = attribute::get(level_control_cluster, LevelControl::Attributes::CurrentLevel::Id); + attribute::set_deferred_persistence(current_level_attribute); + + started = true; + return true; +} + +void MatterDimmableLight::end() { + started = false; +} + +bool MatterDimmableLight::setOnOff(bool newState) { + if (!started) { + log_e("Matter Dimmable Light device has not begun."); + return false; + } + + // avoid processing if there was no change + if (onOffState == newState) { + return true; + } + + onOffState = 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 != onOffState) { + val.val.b = onOffState; + attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); + } + return true; +} + +void MatterDimmableLight::updateAccessory() { + if (_onChangeCB != NULL) { + _onChangeCB(onOffState, brightnessLevel); + } +} + +bool MatterDimmableLight::getOnOff() { + return onOffState; +} + +bool MatterDimmableLight::toggle() { + return setOnOff(!onOffState); +} + +bool MatterDimmableLight::setBrightness(uint8_t newBrightness) { + if (!started) { + log_w("Matter Dimmable Light device has not begun."); + return false; + } + + // avoid processing if there was no change + if (brightnessLevel == newBrightness) { + return true; + } + + brightnessLevel = newBrightness; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, LevelControl::Id); + attribute_t *attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id); + + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + + if (val.val.u8 != brightnessLevel) { + val.val.u8 = brightnessLevel; + attribute::update(endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &val); + } + return true; +} + +uint8_t MatterDimmableLight::getBrightness() { + return brightnessLevel; +} + +MatterDimmableLight::operator bool() { + return getOnOff(); +} + +void MatterDimmableLight::operator=(bool newState) { + setOnOff(newState); +} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterDimmableLight.h b/libraries/Matter/src/MatterEndpoints/MatterDimmableLight.h new file mode 100644 index 00000000000..4497edd2fe2 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterDimmableLight.h @@ -0,0 +1,75 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterDimmableLight : public MatterEndPoint { +public: + static const uint8_t MAX_BRIGHTNESS = 255; + + MatterDimmableLight(); + ~MatterDimmableLight(); + // default initial state is off and brightness is 64 (25%) + virtual bool begin(bool initialState = false, uint8_t brightness = 64); + // this will just stop processing Light Matter events + void end(); + + bool setOnOff(bool newState); // returns true if successful + bool getOnOff(); // returns current light state + bool toggle(); // returns true if successful + + bool setBrightness(uint8_t newBrightness); // returns true if successful + uint8_t getBrightness(); // returns current brightness + + // User Callback for whenever the Light On/Off state is changed by the Matter Controller + using EndPointOnOffCB = std::function; + void onChangeOnOff(EndPointOnOffCB onChangeCB) { + _onChangeOnOffCB = onChangeCB; + } + + // User Callback for whenever the Light brightness value [0..255] is changed by the Matter Controller + using EndPointBrightnessCB = std::function; + void onChangeBrightness(EndPointBrightnessCB onChangeCB) { + _onChangeBrightnessCB = onChangeCB; + } + + // User Callback for whenever any parameter is changed by the Matter Controller + using EndPointCB = std::function; + void onChange(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + + // used to update the state of the light using the current Matter Light internal state + // It is necessary to set a user callback function using onChange() to handle the physical light state + void updateAccessory(); + + operator bool(); // returns current on/off 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); + +protected: + bool started = false; + bool onOffState = false; // default initial state is off, but it can be changed by begin(bool) + uint8_t brightnessLevel = 0; // default initial brightness is 0, but it can be changed by begin(bool, uint8_t) + EndPointOnOffCB _onChangeOnOffCB = NULL; + EndPointBrightnessCB _onChangeBrightnessCB = NULL; + EndPointCB _onChangeCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.cpp b/libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.cpp new file mode 100644 index 00000000000..022e62654df --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.cpp @@ -0,0 +1,394 @@ +// 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 +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +// endpoint for enhanced color light device +namespace esp_matter { +using namespace cluster; +namespace endpoint { +namespace enhanced_color_light { +typedef struct config { + cluster::descriptor::config_t descriptor; + cluster::identify::config_t identify; + cluster::groups::config_t groups; + cluster::scenes_management::config_t scenes_management; + cluster::on_off::config_t on_off; + cluster::level_control::config_t level_control; + cluster::color_control::config_t color_control; +} config_t; + +uint32_t get_device_type_id() { + return ESP_MATTER_EXTENDED_COLOR_LIGHT_DEVICE_TYPE_ID; +} + +uint8_t get_device_type_version() { + return ESP_MATTER_EXTENDED_COLOR_LIGHT_DEVICE_TYPE_VERSION; +} + +esp_err_t add(endpoint_t *endpoint, config_t *config) { + if (!endpoint) { + log_e("Endpoint cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + esp_err_t err = add_device_type(endpoint, get_device_type_id(), get_device_type_version()); + if (err != ESP_OK) { + log_e("Failed to add device type id:%" PRIu32 ",err: %d", get_device_type_id(), err); + return err; + } + + descriptor::create(endpoint, &(config->descriptor), CLUSTER_FLAG_SERVER); + cluster_t *identify_cluster = identify::create(endpoint, &(config->identify), CLUSTER_FLAG_SERVER); + identify::command::create_trigger_effect(identify_cluster); + groups::create(endpoint, &(config->groups), CLUSTER_FLAG_SERVER); + cluster_t *scenes_cluster = scenes_management::create(endpoint, &(config->scenes_management), CLUSTER_FLAG_SERVER); + scenes_management::command::create_copy_scene(scenes_cluster); + scenes_management::command::create_copy_scene_response(scenes_cluster); + + on_off::create(endpoint, &(config->on_off), CLUSTER_FLAG_SERVER, on_off::feature::lighting::get_id()); + level_control::create( + endpoint, &(config->level_control), CLUSTER_FLAG_SERVER, level_control::feature::on_off::get_id() | level_control::feature::lighting::get_id() + ); + color_control::create( + endpoint, &(config->color_control), CLUSTER_FLAG_SERVER, + color_control::feature::hue_saturation::get_id() | color_control::feature::color_temperature::get_id() + ); + return ESP_OK; +} + +endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data) { + endpoint_t *endpoint = endpoint::create(node, flags, priv_data); + add(endpoint, config); + return endpoint; +} +} // namespace enhanced_color_light +} // namespace endpoint +} // namespace esp_matter + +bool MatterEnhancedColorLight::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_e("Matter Enhanced ColorLight device has not begun."); + return false; + } + + log_d( + "Enhanced ColorAttr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u, type: %u", endpoint_id, cluster_id, attribute_id, val->val.u32, + val->type + ); + + if (endpoint_id == getEndPointId()) { + switch (cluster_id) { + case OnOff::Id: + if (attribute_id == OnOff::Attributes::OnOff::Id) { + log_d("Enhanced ColorLight On/Off State changed to %d", val->val.b); + if (_onChangeOnOffCB != NULL) { + ret &= _onChangeOnOffCB(val->val.b); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(val->val.b, colorHSV, brightnessLevel, colorTemperatureLevel); + } + if (ret == true) { + onOffState = val->val.b; + } + } + break; + case LevelControl::Id: + if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) { + log_d("Enhanced ColorLight Brightness changed to %d", val->val.u8); + if (_onChangeBrightnessCB != NULL) { + ret &= _onChangeBrightnessCB(val->val.u8); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(onOffState, colorHSV, val->val.u8, colorTemperatureLevel); + } + if (ret == true) { + colorHSV.v = val->val.u8; + } + } + break; + case ColorControl::Id: + { + if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) { + log_d("Enhanced ColorLight Temperature changed to %d", val->val.u16); + if (_onChangeTemperatureCB != NULL) { + ret &= _onChangeTemperatureCB(val->val.u16); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(onOffState, colorHSV, brightnessLevel, val->val.u16); + } + if (ret == true) { + colorTemperatureLevel = val->val.u16; + } + break; + } + if (attribute_id != ColorControl::Attributes::CurrentHue::Id && attribute_id != ColorControl::Attributes::CurrentSaturation::Id) { + log_i("Color Control Attribute ID [%x] not processed.", attribute_id); + break; + } + espHsvColor_t hsvColor = {colorHSV.h, colorHSV.s, colorHSV.v}; + if (attribute_id == ColorControl::Attributes::CurrentHue::Id) { + log_d("Enhanced ColorLight Hue changed to %d", val->val.u8); + hsvColor.h = val->val.u8; + } else { // attribute_id == ColorControl::Attributes::CurrentSaturation::Id) + log_d("Enhanced ColorLight Saturation changed to %d", val->val.u8); + hsvColor.s = val->val.u8; + } + if (_onChangeColorCB != NULL) { + ret &= _onChangeColorCB(hsvColor); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(onOffState, hsvColor, brightnessLevel, colorTemperatureLevel); + } + if (ret == true) { + colorHSV = {hsvColor.h, hsvColor.s, hsvColor.v}; + } + break; + } + } + } + return ret; +} + +MatterEnhancedColorLight::MatterEnhancedColorLight() {} + +MatterEnhancedColorLight::~MatterEnhancedColorLight() { + end(); +} + +bool MatterEnhancedColorLight::begin(bool initialState, espHsvColor_t _colorHSV, uint8_t brightness, uint16_t ColorTemperature) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter Enhanced ColorLight with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + enhanced_color_light::config_t light_config; + light_config.on_off.on_off = initialState; + light_config.on_off.lighting.start_up_on_off = nullptr; + onOffState = initialState; + + light_config.level_control.current_level = brightness; + light_config.level_control.lighting.start_up_current_level = nullptr; + + light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature; + light_config.color_control.color_temperature.color_temperature_mireds = ColorTemperature; + light_config.color_control.color_temperature.startup_color_temperature_mireds = nullptr; + colorTemperatureLevel = ColorTemperature; + + light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::kCurrentHueAndCurrentSaturation; + light_config.color_control.hue_saturation.current_hue = _colorHSV.h; + light_config.color_control.hue_saturation.current_saturation = _colorHSV.s; + colorHSV = {_colorHSV.h, _colorHSV.s, _colorHSV.v}; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = enhanced_color_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Enhanced ColorLight endpoint"); + return false; + } + + setEndPointId(endpoint::get_id(endpoint)); + log_i("Enhanced ColorLight created with endpoint_id %d", getEndPointId()); + + /* Mark deferred persistence for some attributes that might be changed rapidly */ + cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id); + attribute_t *current_level_attribute = attribute::get(level_control_cluster, LevelControl::Attributes::CurrentLevel::Id); + attribute::set_deferred_persistence(current_level_attribute); + + started = true; + return true; +} + +void MatterEnhancedColorLight::end() { + started = false; +} + +bool MatterEnhancedColorLight::setOnOff(bool newState) { + if (!started) { + log_e("Matter Enhanced ColorLight device has not begun."); + return false; + } + + // avoid processing if there was no change + if (onOffState == newState) { + return true; + } + + onOffState = 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 != onOffState) { + val.val.b = onOffState; + attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); + } + return true; +} + +void MatterEnhancedColorLight::updateAccessory() { + if (_onChangeCB != NULL) { + _onChangeCB(onOffState, colorHSV, brightnessLevel, colorTemperatureLevel); + } +} + +bool MatterEnhancedColorLight::getOnOff() { + return onOffState; +} + +bool MatterEnhancedColorLight::toggle() { + return setOnOff(!onOffState); +} + +bool MatterEnhancedColorLight::setBrightness(uint8_t newBrightness) { + if (!started) { + log_w("Matter Enhanced ColorLight device has not begun."); + return false; + } + + // avoid processing if there was no change + if (brightnessLevel == newBrightness) { + return true; + } + + brightnessLevel = newBrightness; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, LevelControl::Id); + attribute_t *attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id); + + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + + if (val.val.u8 != brightnessLevel) { + val.val.u8 = brightnessLevel; + attribute::update(endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &val); + } + return true; +} + +uint8_t MatterEnhancedColorLight::getBrightness() { + return brightnessLevel; +} + +bool MatterEnhancedColorLight::setColorTemperature(uint16_t newTemperature) { + if (!started) { + log_w("Matter Enhanced ColorLight device has not begun."); + return false; + } + + // avoid processing if there was no change + if (colorTemperatureLevel == newTemperature) { + return true; + } + + colorTemperatureLevel = newTemperature; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, ColorControl::Id); + attribute_t *attribute = attribute::get(cluster, ColorControl::Attributes::ColorTemperatureMireds::Id); + + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + + if (val.val.u16 != colorTemperatureLevel) { + val.val.u16 = colorTemperatureLevel; + attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::ColorTemperatureMireds::Id, &val); + } + return true; +} + +uint16_t MatterEnhancedColorLight::getColorTemperature() { + return colorTemperatureLevel; +} + +bool MatterEnhancedColorLight::setColorRGB(espRgbColor_t _rgbColor) { + return setColorHSV(espRgbColorToHsvColor(_rgbColor)); +} + +espRgbColor_t MatterEnhancedColorLight::getColorRGB() { + return espHsvColorToRgbColor(colorHSV); +} + +bool MatterEnhancedColorLight::setColorHSV(espHsvColor_t _hsvColor) { + + if (!started) { + log_w("Matter Enhanced ColorLight device has not begun."); + return false; + } + + // avoid processing if there was no change + if (colorHSV.h == _hsvColor.h && colorHSV.s == _hsvColor.s && colorHSV.v == _hsvColor.v) { + return true; + } + + colorHSV = {_hsvColor.h, _hsvColor.s, _hsvColor.v}; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, ColorControl::Id); + // update hue + attribute_t *attribute = attribute::get(cluster, ColorControl::Attributes::CurrentHue::Id); + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + if (val.val.u8 != colorHSV.h) { + val.val.u8 = colorHSV.h; + attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::CurrentHue::Id, &val); + } + // update saturation + attribute = attribute::get(cluster, ColorControl::Attributes::CurrentSaturation::Id); + val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + if (val.val.u8 != colorHSV.s) { + val.val.u8 = colorHSV.s; + attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::CurrentSaturation::Id, &val); + } + // update value (brightness) + cluster = cluster::get(endpoint, LevelControl::Id); + attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id); + val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + if (val.val.u8 != colorHSV.v) { + val.val.u8 = colorHSV.v; + attribute::update(endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &val); + } + return true; +} + +espHsvColor_t MatterEnhancedColorLight::getColorHSV() { + return colorHSV; +} + +MatterEnhancedColorLight::operator bool() { + return getOnOff(); +} + +void MatterEnhancedColorLight::operator=(bool newState) { + setOnOff(newState); +} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.h b/libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.h new file mode 100644 index 00000000000..ff6e69e3e65 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.h @@ -0,0 +1,102 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterEnhancedColorLight : public MatterEndPoint { +public: + static const uint8_t MAX_BRIGHTNESS = 255; + static const uint16_t MAX_COLOR_TEMPERATURE = 500; + static const uint16_t MIN_COLOR_TEMPERATURE = 100; + + MatterEnhancedColorLight(); + ~MatterEnhancedColorLight(); + // default initial state is off, brightness = 25 (10%), HSV(21, 216, 25), color temperature is 454 (Warm White) + virtual bool begin(bool initialState = false, espHsvColor_t colorHSV = {21, 216, 25}, uint8_t newBrightness = 25, uint16_t colorTemperature = 454); + // this will just stop processing Light Matter events + void end(); + + bool setOnOff(bool newState); // returns true if successful + bool getOnOff(); // returns current light state + bool toggle(); // returns true if successful + + bool setColorTemperature(uint16_t newTemperature); // returns true if successful + uint16_t getColorTemperature(); // returns current temperature + + bool setBrightness(uint8_t newBrightness); // returns true if successful + uint8_t getBrightness(); // returns current brightness + + bool setColorRGB(espRgbColor_t rgbColor); // returns true if successful + espRgbColor_t getColorRGB(); // returns current RGB Color + bool setColorHSV(espHsvColor_t hsvColor); // returns true if successful + espHsvColor_t getColorHSV(); // returns current HSV Color + + // User Callback for whenever the Light On/Off state is changed by the Matter Controller + using EndPointOnOffCB = std::function; + void onChangeOnOff(EndPointOnOffCB onChangeCB) { + _onChangeOnOffCB = onChangeCB; + } + + // User Callback for whenever the Light brightness value [0..255] is changed by the Matter Controller + using EndPointBrightnessCB = std::function; + void onChangeBrightness(EndPointBrightnessCB onChangeCB) { + _onChangeBrightnessCB = onChangeCB; + } + + // User Callback for whenever the HSV Color value is changed by the Matter Controller + using EndPointRGBColorCB = std::function; + void onChangeColorHSV(EndPointRGBColorCB onChangeCB) { + _onChangeColorCB = onChangeCB; + } + + // User Callbqck for whenever the Light temperature value is changed by the Matter Controller + using EndPointTemperatureCB = std::function; + void onChangeColorTemperature(EndPointTemperatureCB onChangeCB) { + _onChangeTemperatureCB = onChangeCB; + } + + // User Callback for whenever any parameter is changed by the Matter Controller + using EndPointCB = std::function; + void onChange(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + + // used to update the state of the light using the current Matter Light internal state + // It is necessary to set a user callback function using onChange() to handle the physical light state + void updateAccessory(); + + operator bool(); // returns current on/off 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); + +protected: + bool started = false; + bool onOffState = false; // default initial state is off, but it can be changed by begin(bool) + uint8_t brightnessLevel = 0; // default initial brightness is 0, but it can be changed by begin(bool, uint8_t) + espHsvColor_t colorHSV = {0}; // default initial color HSV is black, but it can be changed by begin(bool, uint8_t, espHsvColor_t) + uint16_t colorTemperatureLevel = 0; // default initial color temperature is 0, but it can be changed by begin(bool, uint8_t, espHsvColor_t, uint16_t) + EndPointOnOffCB _onChangeOnOffCB = NULL; + EndPointBrightnessCB _onChangeBrightnessCB = NULL; + EndPointRGBColorCB _onChangeColorCB = NULL; + EndPointTemperatureCB _onChangeTemperatureCB = NULL; + EndPointCB _onChangeCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterFan.cpp b/libraries/Matter/src/MatterEndpoints/MatterFan.cpp new file mode 100644 index 00000000000..1647490aa05 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterFan.cpp @@ -0,0 +1,235 @@ +// 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 +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace esp_matter::cluster; +using namespace chip::app::Clusters; + +// string helper for the FAN MODE +const char *MatterFan::fanModeString[7] = {"OFF", "LOW", "MEDIUM", "HIGH", "ON", "AUTO", "SMART"}; +// bitmap for valid Fan Modes based on order defined in Zap Generated Cluster Enums +const uint8_t MatterFan::fanModeSequence[6] = {fanSeqModeOffLowMedHigh, fanSeqModeOffLowHigh, fanSeqModeOffLowMedHighAuto, + fanSeqModeOffLowHighAuto, fanSeqModeOffHighAuto, fanSeqModeOffHigh}; + +// Constructor and Method Definitions +MatterFan::MatterFan() {} + +MatterFan::~MatterFan() { + end(); +} + +bool MatterFan::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_e("Matter Fan device has not begun."); + return false; + } + + log_d("Fan Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + + if (endpoint_id == getEndPointId() && cluster_id == FanControl::Id) { + switch (attribute_id) { + case FanControl::Attributes::FanMode::Id: + log_v("FanControl Fan Mode changed to %s (%x)", val->val.u8 < 7 ? fanModeString[val->val.u8] : "Unknown", val->val.u8); + if (_onChangeModeCB != NULL) { + ret &= _onChangeModeCB((FanMode_t)val->val.u8); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB((FanMode_t)val->val.u8, currentPercent); + } + if (ret == true) { + currentFanMode = (FanMode_t)val->val.u8; + } + break; + case FanControl::Attributes::PercentSetting::Id: + case FanControl::Attributes::PercentCurrent::Id: + log_v("FanControl Percent %s changed to %d", attribute_id == FanControl::Attributes::PercentSetting::Id ? "SETTING" : "CURRENT", val->val.u8); + if (_onChangeSpeedCB != NULL) { + ret &= _onChangeSpeedCB(val->val.u8); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(currentFanMode, val->val.u8); + } + if (ret == true) { + // change setting speed percent + currentPercent = val->val.u8; + setAttributeVal(FanControl::Id, FanControl::Attributes::PercentSetting::Id, val); + setAttributeVal(FanControl::Id, FanControl::Attributes::PercentCurrent::Id, val); + } + break; + } + } + + return ret; +} + +bool MatterFan::begin(uint8_t percent, FanMode_t fanMode, FanModeSequence_t fanModeSeq) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter Fan with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + // endpoint handles can be used to add/modify clusters. + fan::config_t fan_config; + fan_config.fan_control.fan_mode = fanMode; + fan_config.fan_control.percent_current = percent; + fan_config.fan_control.percent_setting = percent; + fan_config.fan_control.fan_mode_sequence = fanModeSeq; + validFanModes = fanModeSequence[fanModeSeq]; + + endpoint_t *endpoint = fan::create(node::get(), &fan_config, ENDPOINT_FLAG_NONE, (void *)this); + + if (endpoint == nullptr) { + log_e("Failed to create Fan endpoint"); + return false; + } + + currentFanMode = fanMode; + currentPercent = percent; + + setEndPointId(endpoint::get_id(endpoint)); + log_i("Fan created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterFan::end() { + started = false; +} + +bool MatterFan::setMode(FanMode_t newMode, bool performUpdate) { + if (!started) { + log_w("Matter Fan device has not begun."); + return false; + } + // avoid processing if there was no change + if (currentFanMode == newMode) { + return true; + } + + // check if the mode is valid based on the sequence used in its creation + if (!(validFanModes & (1 << newMode))) { + log_e("Invalid Fan Mode %s for the current Fan Mode Sequence.", fanModeString[newMode]); + return false; + } + + esp_matter_attr_val_t modeVal = esp_matter_invalid(NULL); + if (!getAttributeVal(FanControl::Id, FanControl::Attributes::FanMode::Id, &modeVal)) { + log_e("Failed to get Fan Mode Attribute."); + return false; + } + if (modeVal.val.u8 != (uint8_t)newMode) { + modeVal.val.u8 = (uint8_t)newMode; + bool ret; + if (performUpdate) { + ret = updateAttributeVal(FanControl::Id, FanControl::Attributes::FanMode::Id, &modeVal); + } else { + ret = setAttributeVal(FanControl::Id, FanControl::Attributes::FanMode::Id, &modeVal); + } + if (!ret) { + log_e("Failed to %s Fan Mode Attribute.", performUpdate ? "update" : "set"); + return false; + } + } + currentFanMode = newMode; + log_v("Fan Mode %s to %s ==> onOffState[%s]", performUpdate ? "updated" : "set", fanModeString[currentFanMode], getOnOff() ? "ON" : "OFF"); + return true; +} + +// this function will change the Fan Speed by calling the user application callback +// it is up to the application to decide to turn on, off or change the speed of the fan +bool MatterFan::setSpeedPercent(uint8_t newPercent, bool performUpdate) { + if (!started) { + log_w("Matter Fan device has not begun."); + return false; + } + // avoid processing if there was no change + if (currentPercent == newPercent) { + return true; + } + + esp_matter_attr_val_t speedVal = esp_matter_invalid(NULL); + if (!getAttributeVal(FanControl::Id, FanControl::Attributes::PercentSetting::Id, &speedVal)) { + log_e("Failed to get Fan Speed Percent Attribute."); + return false; + } + if (speedVal.val.u8 != newPercent) { + speedVal.val.u8 = newPercent; + bool ret; + if (performUpdate) { + ret = updateAttributeVal(FanControl::Id, FanControl::Attributes::PercentSetting::Id, &speedVal); + } else { + ret = setAttributeVal(FanControl::Id, FanControl::Attributes::PercentSetting::Id, &speedVal); + ret = setAttributeVal(FanControl::Id, FanControl::Attributes::PercentCurrent::Id, &speedVal); + } + if (!ret) { + log_e("Failed to %s Fan Speed Percent Attribute.", performUpdate ? "update" : "set"); + return false; + } + } + currentPercent = newPercent; + log_v("Fan Speed %s to %d ==> onOffState[%s]", performUpdate ? "updated" : "set", currentPercent, getOnOff() ? "ON" : "OFF"); + return true; +} + +bool MatterFan::setOnOff(bool newState, bool performUpdate) { + if (!started) { + log_w("Matter Fan device has not begun."); + return false; + } + // avoid processing if there was no change + if (getOnOff() == newState) { + return true; + } + + esp_matter_attr_val_t modeVal = esp_matter_invalid(NULL); + if (!getAttributeVal(FanControl::Id, FanControl::Attributes::FanMode::Id, &modeVal)) { + log_e("Failed to get Fan Mode Attribute."); + return false; + } + if (modeVal.val.u8 != (uint8_t)newState) { + FanMode_t newMode = newState ? FAN_MODE_ON : FAN_MODE_OFF; + if (!setMode(newMode, performUpdate)) { + return false; + } + } + log_v( + "Fan State %s to %s :: Mode[%s]|Speed[%d]", performUpdate ? "updated" : "set", getOnOff() ? "ON" : "OFF", fanModeString[currentFanMode], currentPercent + ); + return true; +} + +bool MatterFan::getOnOff() { + return currentFanMode == FAN_MODE_OFF ? false : true; +} + +bool MatterFan::toggle(bool performUpdate) { + if (getOnOff() == true) { + return setOnOff(false, performUpdate); + } else { + return setOnOff(true, performUpdate); + } +} + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterFan.h b/libraries/Matter/src/MatterEndpoints/MatterFan.h new file mode 100644 index 00000000000..a1cd6e42423 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterFan.h @@ -0,0 +1,164 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace chip::app::Clusters::FanControl; + +// Matter Fan endpoint with On/Off, Mode and Speed control + +class MatterFan : public MatterEndPoint { +public: + // Fan feature constants + static const uint8_t MAX_SPEED = 100; // maximum High speed + static const uint8_t MIN_SPEED = 1; // minimum Low speed + static const uint8_t OFF_SPEED = 0; // speed set by Matter when FAN_MODE_OFF + + // Default Fan Modes: ON, SMART, HIGH and OFF + + // Other mode will depend on what is the configured Fan Mode Sequence + enum FanMode_t { + FAN_MODE_OFF = (uint8_t)FanModeEnum::kOff, + FAN_MODE_LOW = (uint8_t)FanModeEnum::kLow, + FAN_MODE_MEDIUM = (uint8_t)FanModeEnum::kMedium, + FAN_MODE_HIGH = (uint8_t)FanModeEnum::kHigh, + FAN_MODE_ON = (uint8_t)FanModeEnum::kOn, + FAN_MODE_AUTO = (uint8_t)FanModeEnum::kAuto, + FAN_MODE_SMART = (uint8_t)FanModeEnum::kSmart + }; + + // Menu will always have ON, OFF, HIGH and SMART. + // AUTO will show up only when a AUTO SEQ is CONFIGURED + // LOW and MEDIUM depend on the SEQ MODE configuration + enum FanModeSequence_t { + FAN_MODE_SEQ_OFF_LOW_MED_HIGH = (uint8_t)FanModeSequenceEnum::kOffLowMedHigh, + FAN_MODE_SEQ_OFF_LOW_HIGH = (uint8_t)FanModeSequenceEnum::kOffLowHigh, + FAN_MODE_SEQ_OFF_LOW_MED_HIGH_AUTO = (uint8_t)FanModeSequenceEnum::kOffLowMedHighAuto, + FAN_MODE_SEQ_OFF_LOW_HIGH_AUTO = (uint8_t)FanModeSequenceEnum::kOffLowHighAuto, + FAN_MODE_SEQ_OFF_HIGH_AUTO = (uint8_t)FanModeSequenceEnum::kOffHighAuto, + FAN_MODE_SEQ_OFF_HIGH = (uint8_t)FanModeSequenceEnum::kOffHigh + }; + + MatterFan(); + ~MatterFan(); + virtual bool begin(uint8_t percent = 0, FanMode_t fanMode = FAN_MODE_OFF, FanModeSequence_t fanModeSeq = FAN_MODE_SEQ_OFF_HIGH); + void end(); // this will just stop processing Matter events + + // returns a friendly string for the Fan Mode + static const char *getFanModeString(uint8_t mode) { + return fanModeString[mode]; + } + + // Fan Control of current On/Off state + + bool setOnOff(bool newState, bool performUpdate = true); // sets Fan On/Off state + bool getOnOff(); // returns current Fan state + bool toggle(bool performUpdate = true); // toggle Fun On/Off state + + // Fan Control of current speed percent + + bool setSpeedPercent(uint8_t newPercent, bool performUpdate = true); // returns true if successful + uint8_t getSpeedPercent() { // returns current Fan Speed Percent + return currentPercent; + } + + // Fan Control of current Fan Mode + + bool setMode(FanMode_t newMode, bool performUpdate = true); // returns true if successful + FanMode_t getMode() { // returns current Fan Mode + return currentFanMode; + } + // used to update the state of the Fan using the current Matter Fan internal state + // It is necessary to set a user callback function using onChange() to handle the physical Fan motor state + + void updateAccessory() { + if (_onChangeCB != NULL) { + _onChangeCB(currentFanMode, currentPercent); + } + } + + // returns current Fan speed percent + operator uint8_t() { + return getSpeedPercent(); + } + + // User Callback for whenever the Fan Mode (state) is changed by the Matter Controller + using EndPointModeCB = std::function; + void onChangeMode(EndPointModeCB onChangeCB) { + _onChangeModeCB = onChangeCB; + } + + // User Callback for whenever the Fan Speed Percentage value [0..100] is changed by the Matter Controller + using EndPointSpeedCB = std::function; + void onChangeSpeedPercent(EndPointSpeedCB onChangeCB) { + _onChangeSpeedCB = onChangeCB; + } + + // User Callback for whenever any parameter is changed by the Matter Controller + using EndPointCB = std::function; + void onChange(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + + // sets Fan speed percent + void operator=(uint8_t speedPercent) { + setSpeedPercent(speedPercent); + } + + // 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); + +protected: + bool started = false; + uint8_t validFanModes = 0; // bitmap for valid Fan Modes - index of fanModeSequence[] + + uint8_t currentPercent = 0; // current speed percent + FanMode_t currentFanMode = FAN_MODE_OFF; // current Fan Mode + EndPointModeCB _onChangeModeCB = NULL; + EndPointSpeedCB _onChangeSpeedCB = NULL; + EndPointCB _onChangeCB = NULL; + + // bitmap for Fan Sequence Modes (OFF, LOW, MEDIUM, HIGH, AUTO) + static const uint8_t fanSeqModeOff = 0x01; + static const uint8_t fanSeqModeLow = 0x02; + static const uint8_t fanSeqModeMedium = 0x04; + static const uint8_t fanSeqModeHigh = 0x08; + static const uint8_t fanSeqModeOn = 0x10; + static const uint8_t fanSeqModeAuto = 0x20; + static const uint8_t fanSeqModeSmart = 0x40; + + // bitmap for common modes: ON, OFF, HIGH and SMART + static const uint8_t fanSeqCommonModes = fanSeqModeOff | fanSeqModeOn | fanSeqModeHigh | fanSeqModeSmart; + + static const uint8_t fanSeqModeOffLowMedHigh = fanSeqCommonModes | fanSeqModeLow | fanSeqModeMedium; + static const uint8_t fanSeqModeOffLowHigh = fanSeqCommonModes | fanSeqModeLow; + static const uint8_t fanSeqModeOffLowMedHighAuto = fanSeqCommonModes | fanSeqModeLow | fanSeqModeMedium | fanSeqModeAuto; + static const uint8_t fanSeqModeOffLowHighAuto = fanSeqCommonModes | fanSeqModeLow | fanSeqModeAuto; + static const uint8_t fanSeqModeOffHighAuto = fanSeqCommonModes | fanSeqModeAuto; + static const uint8_t fanSeqModeOffHigh = fanSeqCommonModes; + + // bitmap for valid Fan Modes based on order defined in Zap Generated Cluster Enums + static const uint8_t fanModeSequence[6]; + + // string helper for the FAN MODE + static const char *fanModeString[7]; +}; + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp new file mode 100644 index 00000000000..e20479af088 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp @@ -0,0 +1,105 @@ +// 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 +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace esp_matter::cluster; +using namespace chip::app::Clusters; + +MatterGenericSwitch::MatterGenericSwitch() {} + +MatterGenericSwitch::~MatterGenericSwitch() { + end(); +} + +bool MatterGenericSwitch::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) { + if (!started) { + log_e("Matter Generic Switch device has not begun."); + return false; + } + + log_d("Generic Switch Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + return true; +} + +bool MatterGenericSwitch::begin() { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter Generic Switch with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + generic_switch::config_t switch_config; + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = generic_switch::create(node::get(), &switch_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Generic Switch endpoint"); + return false; + } + // Add group cluster to the switch endpoint + cluster::groups::config_t groups_config; + cluster::groups::create(endpoint, &groups_config, CLUSTER_FLAG_SERVER | CLUSTER_FLAG_CLIENT); + + cluster_t *aCluster = cluster::get(endpoint, Descriptor::Id); + esp_matter::cluster::descriptor::feature::taglist::add(aCluster); + + cluster::fixed_label::config_t fl_config; + cluster::fixed_label::create(endpoint, &fl_config, CLUSTER_FLAG_SERVER); + + cluster::user_label::config_t ul_config; + cluster::user_label::create(endpoint, &ul_config, CLUSTER_FLAG_SERVER); + + aCluster = cluster::get(endpoint, Switch::Id); + switch_cluster::feature::momentary_switch::add(aCluster); + switch_cluster::event::create_initial_press(aCluster); + + switch_cluster::feature::momentary_switch::add(aCluster); + + switch_cluster::attribute::create_current_position(aCluster, 0); + switch_cluster::attribute::create_number_of_positions(aCluster, 2); + + setEndPointId(endpoint::get_id(endpoint)); + log_i("Generic Switch created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterGenericSwitch::end() { + started = false; +} + +void MatterGenericSwitch::click() { + if (!started) { + log_e("Matter Generic Switch device has not begun."); + return; + } + + int switch_endpoint_id = getEndPointId(); + uint8_t newPosition = 1; + // Press moves Position from 0 (off) to 1 (on) + chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, newPosition]() { + // InitialPress event takes newPosition as event data + switch_cluster::event::send_initial_press(switch_endpoint_id, newPosition); + }); +} + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h new file mode 100644 index 00000000000..14118462932 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h @@ -0,0 +1,39 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +// Matter Generic Switch Endpoint that works as a single click smart button +class MatterGenericSwitch : public MatterEndPoint { +public: + MatterGenericSwitch(); + ~MatterGenericSwitch(); + virtual bool begin(); + void end(); // this will just stop processing Matter events + + // send a simple click event to the Matter Controller + void click(); + + // 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); + +protected: + bool started = false; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.cpp b/libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.cpp new file mode 100644 index 00000000000..d31d0e43728 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.cpp @@ -0,0 +1,116 @@ +// 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 +#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 MatterHumiditySensor::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_e("Matter Humidity Sensor device has not begun."); + return false; + } + + log_d("Humidity Sensor Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + return ret; +} + +MatterHumiditySensor::MatterHumiditySensor() {} + +MatterHumiditySensor::~MatterHumiditySensor() { + end(); +} + +bool MatterHumiditySensor::begin(uint16_t _rawHumidity) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter Humidity Sensor with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + // is it a valid percentage value? + if (_rawHumidity > 10000) { + log_e("Humidity Sensor Percentage value out of range [0..100]."); + return false; + } + + humidity_sensor::config_t humidity_sensor_config; + humidity_sensor_config.relative_humidity_measurement.measured_value = _rawHumidity; + humidity_sensor_config.relative_humidity_measurement.min_measured_value = nullptr; + humidity_sensor_config.relative_humidity_measurement.max_measured_value = nullptr; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = humidity_sensor::create(node::get(), &humidity_sensor_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Humidity Sensor endpoint"); + return false; + } + rawHumidity = _rawHumidity; + setEndPointId(endpoint::get_id(endpoint)); + log_i("Humidity Sensor created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterHumiditySensor::end() { + started = false; +} + +bool MatterHumiditySensor::setRawHumidity(uint16_t _rawHumidity) { + if (!started) { + log_e("Matter Humidity Sensor device has not begun."); + return false; + } + // is it a valid percentage value? + if (_rawHumidity > 10000) { + log_e("Humidity Sensor Percentage value out of range [0..100]."); + return false; + } + + // avoid processing if there was no change + if (rawHumidity == _rawHumidity) { + return true; + } + + esp_matter_attr_val_t humidityVal = esp_matter_invalid(NULL); + + if (!getAttributeVal(RelativeHumidityMeasurement::Id, RelativeHumidityMeasurement::Attributes::MeasuredValue::Id, &humidityVal)) { + log_e("Failed to get Humidity Sensor Attribute."); + return false; + } + if (humidityVal.val.u16 != _rawHumidity) { + humidityVal.val.u16 = _rawHumidity; + bool ret; + ret = updateAttributeVal(RelativeHumidityMeasurement::Id, RelativeHumidityMeasurement::Attributes::MeasuredValue::Id, &humidityVal); + if (!ret) { + log_e("Failed to update Humidity Sensor Attribute."); + return false; + } + rawHumidity = _rawHumidity; + } + log_v("Humidity Sensor set to %.02f Percent", (float)_rawHumidity / 100.00); + + return true; +} + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.h b/libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.h new file mode 100644 index 00000000000..aed758b7b7a --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.h @@ -0,0 +1,69 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterHumiditySensor : public MatterEndPoint { +public: + MatterHumiditySensor(); + ~MatterHumiditySensor(); + // begin Matter Humidity Sensor endpoint with initial float humidity percent + bool begin(double humidityPercent = 0.00) { + if (humidityPercent < 0.0 || humidityPercent > 100.0) { + log_e("Humidity Sensor Percentage value out of range [0..100]."); + return false; + } + return begin(static_cast(humidityPercent * 100.0f)); + } + // this will just stop processing Humidity Sensor Matter events + void end(); + + // set the humidity percent with 1/100th of a percent precision + bool setHumidity(double humidityPercent) { + if (humidityPercent < 0.0 || humidityPercent > 100.0) { + log_e("Humidity Sensor Percentage value out of range [0..100]."); + return false; + } + return setRawHumidity(static_cast(humidityPercent * 100.0f)); + } + // returns the reported float humidity percent with 1/100th of precision + double getHumidity() { + return (double)rawHumidity / 100.0; + } + // double conversion operator + void operator=(double humidityPercent) { + setHumidity(humidityPercent); + } + // double conversion operator + operator double() { + return (double)getHumidity(); + } + + // 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); + +protected: + bool started = false; + // implementation keeps humidity relative percentage with 1/100th of a percent precision + uint16_t rawHumidity = 0; + // internal function to set the raw humidity value (Matter Cluster) + bool begin(uint16_t _rawHumidity); + bool setRawHumidity(uint16_t _rawHumidity); +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp b/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp new file mode 100644 index 00000000000..0d55c37708a --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp @@ -0,0 +1,114 @@ +// 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 +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +// clang-format off +const uint8_t MatterOccupancySensor::occupancySensorTypeBitmap[4] = { + MatterOccupancySensor::occupancySensorTypePir, + MatterOccupancySensor::occupancySensorTypePir | MatterOccupancySensor::occupancySensorTypeUltrasonic, + MatterOccupancySensor::occupancySensorTypeUltrasonic, + MatterOccupancySensor::occupancySensorTypePhysicalContact +}; +// clang-format on + +bool MatterOccupancySensor::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_e("Matter Occupancy Sensor device has not begun."); + return false; + } + + log_d("Occupancy Sensor Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + return ret; +} + +MatterOccupancySensor::MatterOccupancySensor() {} + +MatterOccupancySensor::~MatterOccupancySensor() { + end(); +} + +bool MatterOccupancySensor::begin(bool _occupancyState, OccupancySensorType_t _occupancySensorType) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter Occupancy Sensor with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + occupancy_sensor::config_t occupancy_sensor_config; + occupancy_sensor_config.occupancy_sensing.occupancy = _occupancyState; + occupancy_sensor_config.occupancy_sensing.occupancy_sensor_type = _occupancySensorType; + occupancy_sensor_config.occupancy_sensing.occupancy_sensor_type_bitmap = occupancySensorTypeBitmap[_occupancySensorType]; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = occupancy_sensor::create(node::get(), &occupancy_sensor_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Occupancy Sensor endpoint"); + return false; + } + occupancyState = _occupancyState; + setEndPointId(endpoint::get_id(endpoint)); + log_i("Occupancy Sensor created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterOccupancySensor::end() { + started = false; +} + +bool MatterOccupancySensor::setOccupancy(bool _occupancyState) { + if (!started) { + log_e("Matter Occupancy Sensor device has not begun."); + return false; + } + + // avoid processing if there was no change + if (occupancyState == _occupancyState) { + return true; + } + + esp_matter_attr_val_t occupancyVal = esp_matter_invalid(NULL); + + if (!getAttributeVal(OccupancySensing::Id, OccupancySensing::Attributes::Occupancy::Id, &occupancyVal)) { + log_e("Failed to get Occupancy Sensor Attribute."); + return false; + } + if (occupancyVal.val.u8 != _occupancyState) { + occupancyVal.val.u8 = _occupancyState; + bool ret; + ret = updateAttributeVal(OccupancySensing::Id, OccupancySensing::Attributes::Occupancy::Id, &occupancyVal); + if (!ret) { + log_e("Failed to update Occupancy Sensor Attribute."); + return false; + } + occupancyState = _occupancyState; + } + log_v("Occupancy Sensor set to %s", _occupancyState ? "Occupied" : "Vacant"); + + return true; +} + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h b/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h new file mode 100644 index 00000000000..30f312a9841 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h @@ -0,0 +1,73 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace chip::app::Clusters::OccupancySensing; + +class MatterOccupancySensor : public MatterEndPoint { +public: + // Different Occupancy Sensor Types + enum OccupancySensorType_t { + OCCUPANCY_SENSOR_TYPE_PIR = (uint8_t)OccupancySensorTypeEnum::kPir, + OCCUPANCY_SENSOR_TYPE_ULTRASONIC = (uint8_t)OccupancySensorTypeEnum::kUltrasonic, + OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC = (uint8_t)OccupancySensorTypeEnum::kPIRAndUltrasonic, + OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT = (uint8_t)OccupancySensorTypeEnum::kPhysicalContact + }; + + MatterOccupancySensor(); + ~MatterOccupancySensor(); + // begin Matter Occupancy Sensor endpoint with initial occupancy state and default PIR sensor type + bool begin(bool _occupancyState = false, OccupancySensorType_t _occupancySensorType = OCCUPANCY_SENSOR_TYPE_PIR); + // this will just stop processing Occupancy Sensor Matter events + void end(); + + // set the occupancy state + bool setOccupancy(bool _occupancyState); + // returns the occupancy state + bool getOccupancy() { + return occupancyState; + } + + // bool conversion operator + void operator=(bool _occupancyState) { + setOccupancy(_occupancyState); + } + // bool conversion operator + operator bool() { + return getOccupancy(); + } + + // 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); + +protected: + // bitmap for Occupancy Sensor Types + static const uint8_t occupancySensorTypePir = 0x01; + static const uint8_t occupancySensorTypeUltrasonic = 0x02; + static const uint8_t occupancySensorTypePhysicalContact = 0x04; + + // bitmap for Occupancy Sensor Type Bitmap mapped array + static const uint8_t occupancySensorTypeBitmap[4]; + + bool started = false; + bool occupancyState = false; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterOnOffLight.cpp b/libraries/Matter/src/MatterEndpoints/MatterOnOffLight.cpp new file mode 100644 index 00000000000..3faba821528 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterOnOffLight.cpp @@ -0,0 +1,138 @@ +// 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 +#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_e("Matter On-Off Light device has not begun."); + return false; + } + + log_d("OnOff Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + + if (endpoint_id == getEndPointId()) { + log_d("OnOffLight state changed to %d", val->val.b); + if (cluster_id == OnOff::Id) { + if (attribute_id == OnOff::Attributes::OnOff::Id) { + if (_onChangeOnOffCB != NULL) { + ret &= _onChangeOnOffCB(val->val.b); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(val->val.b); + } + if (ret == true) { + onOffState = val->val.b; + } + } + } + } + return ret; +} + +MatterOnOffLight::MatterOnOffLight() {} + +MatterOnOffLight::~MatterOnOffLight() { + end(); +} + +bool MatterOnOffLight::begin(bool initialState) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter On-Off Light with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + on_off_light::config_t light_config; + light_config.on_off.on_off = initialState; + light_config.on_off.lighting.start_up_on_off = nullptr; + onOffState = initialState; + + // 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; +} + +void MatterOnOffLight::updateAccessory() { + if (_onChangeCB != NULL) { + _onChangeCB(onOffState); + } +} + +bool MatterOnOffLight::setOnOff(bool newState) { + if (!started) { + log_e("Matter On-Off Light device has not begun."); + return false; + } + + // avoid processing if there was no change + if (onOffState == newState) { + return true; + } + + onOffState = 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 != onOffState) { + val.val.b = onOffState; + attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); + } + return true; +} + +bool MatterOnOffLight::getOnOff() { + return onOffState; +} + +bool MatterOnOffLight::toggle() { + return setOnOff(!onOffState); +} + +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/MatterEndpoints/MatterOnOffLight.h b/libraries/Matter/src/MatterEndpoints/MatterOnOffLight.h new file mode 100644 index 00000000000..ec524d2c300 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterOnOffLight.h @@ -0,0 +1,60 @@ +// 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 +#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 + + // User Callback for whenever the Light state is changed by the Matter Controller + using EndPointCB = std::function; + void onChange(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + + // User Callback for whenever the Light On/Off state is changed by the Matter Controller + void onChangeOnOff(EndPointCB onChangeCB) { + _onChangeOnOffCB = onChangeCB; + } + + // used to update the state of the light using the current Matter Light internal state + // It is necessary to set a user callback function using onChange() to handle the physical light state + void updateAccessory(); + + 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); + +protected: + bool started = false; + bool onOffState = false; // default initial state is off, but it can be changed by begin(bool) + EndPointCB _onChangeCB = NULL; + EndPointCB _onChangeOnOffCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.cpp b/libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.cpp new file mode 100644 index 00000000000..9b08958684c --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.cpp @@ -0,0 +1,141 @@ +// 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 +#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 MatterOnOffPlugin::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_e("Matter On-Off Plugin device has not begun."); + return false; + } + + log_d("OnOff Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + + if (endpoint_id == getEndPointId()) { + log_d("OnOffPlugin state changed to %d", val->val.b); + if (cluster_id == OnOff::Id) { + if (attribute_id == OnOff::Attributes::OnOff::Id) { + if (_onChangeOnOffCB != NULL) { + ret &= _onChangeOnOffCB(val->val.b); + } + if (_onChangeCB != NULL) { + ret &= _onChangeCB(val->val.b); + } + if (ret == true) { + onOffState = val->val.b; + } + } + } + } + return ret; +} + +MatterOnOffPlugin::MatterOnOffPlugin() {} + +MatterOnOffPlugin::~MatterOnOffPlugin() { + end(); +} + +bool MatterOnOffPlugin::begin(bool initialState) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter On-Off Plugin with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + on_off_plugin_unit::config_t plugin_config; + plugin_config.on_off.on_off = initialState; + plugin_config.on_off.lighting.start_up_on_off = nullptr; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = on_off_plugin_unit::create(node::get(), &plugin_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create on-off plugin endpoint"); + return false; + } + onOffState = initialState; + setEndPointId(endpoint::get_id(endpoint)); + log_i("On-Off Plugin created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterOnOffPlugin::end() { + started = false; +} + +void MatterOnOffPlugin::updateAccessory() { + if (_onChangeCB != NULL) { + _onChangeCB(onOffState); + } +} + +bool MatterOnOffPlugin::setOnOff(bool newState) { + if (!started) { + log_e("Matter On-Off Plugin device has not begun."); + return false; + } + + // avoid processing if there was no change + if (onOffState == newState) { + return true; + } + + esp_matter_attr_val_t onoffVal = esp_matter_invalid(NULL); + + if (!getAttributeVal(OnOff::Id, OnOff::Attributes::OnOff::Id, &onoffVal)) { + log_e("Failed to get Pressure Sensor Attribute."); + return false; + } + if (onoffVal.val.b != newState) { + onoffVal.val.b = newState; + bool ret; + ret = updateAttributeVal(OnOff::Id, OnOff::Attributes::OnOff::Id, &onoffVal); + if (!ret) { + log_e("Failed to update Pressure Sensor Measurement Attribute."); + return false; + } + onOffState = newState; + } + log_v("Plugin OnOff state set to %s", newState ? "ON" : "OFF"); + return true; +} + +bool MatterOnOffPlugin::getOnOff() { + return onOffState; +} + +bool MatterOnOffPlugin::toggle() { + return setOnOff(!onOffState); +} + +MatterOnOffPlugin::operator bool() { + return getOnOff(); +} + +void MatterOnOffPlugin::operator=(bool newState) { + setOnOff(newState); +} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.h b/libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.h new file mode 100644 index 00000000000..0b05c0944c4 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.h @@ -0,0 +1,60 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterOnOffPlugin : public MatterEndPoint { +public: + MatterOnOffPlugin(); + ~MatterOnOffPlugin(); + virtual bool begin(bool initialState = false); // default initial state is off + void end(); // this will just stop processing Plugin Matter events + + bool setOnOff(bool newState); // returns true if successful + bool getOnOff(); // returns current plugin state + bool toggle(); // returns true if successful + + // User Callback for whenever the Plugin state is changed by the Matter Controller + using EndPointCB = std::function; + void onChange(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + + // User Callback for whenever the On/Off state is changed by the Matter Controller + void onChangeOnOff(EndPointCB onChangeCB) { + _onChangeOnOffCB = onChangeCB; + } + + // used to update the state of the plugin using the current Matter Plugin internal state + // It is necessary to set a user callback function using onChange() to handle the physical plugin state + void updateAccessory(); + + operator bool(); // returns current plugin state + void operator=(bool state); // turns plugin 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); + +protected: + bool started = false; + bool onOffState = false; // default initial state is off, but it can be changed by begin(bool) + EndPointCB _onChangeCB = NULL; + EndPointCB _onChangeOnOffCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterPressureSensor.cpp b/libraries/Matter/src/MatterEndpoints/MatterPressureSensor.cpp new file mode 100644 index 00000000000..86d245d4041 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterPressureSensor.cpp @@ -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. + +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +bool MatterPressureSensor::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_e("Matter Pressure Sensor device has not begun."); + return false; + } + + log_d("Pressure Sensor Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + return ret; +} + +MatterPressureSensor::MatterPressureSensor() {} + +MatterPressureSensor::~MatterPressureSensor() { + end(); +} + +bool MatterPressureSensor::begin(int16_t _rawPressure) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Matter Pressure Sensor with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + pressure_sensor::config_t pressure_sensor_config; + pressure_sensor_config.pressure_measurement.pressure_measured_value = _rawPressure; + pressure_sensor_config.pressure_measurement.pressure_min_measured_value = nullptr; + pressure_sensor_config.pressure_measurement.pressure_max_measured_value = nullptr; + + // endpoint handles can be used to add/modify clusters + endpoint_t *endpoint = pressure_sensor::create(node::get(), &pressure_sensor_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Pressure Sensor endpoint"); + return false; + } + rawPressure = _rawPressure; + setEndPointId(endpoint::get_id(endpoint)); + log_i("Pressure Sensor created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterPressureSensor::end() { + started = false; +} + +bool MatterPressureSensor::setRawPressure(int16_t _rawPressure) { + if (!started) { + log_e("Matter Pressure Sensor device has not begun."); + return false; + } + + // avoid processing if there was no change + if (rawPressure == _rawPressure) { + return true; + } + + esp_matter_attr_val_t pressureVal = esp_matter_invalid(NULL); + + if (!getAttributeVal(PressureMeasurement::Id, PressureMeasurement::Attributes::MeasuredValue::Id, &pressureVal)) { + log_e("Failed to get Pressure Sensor Attribute."); + return false; + } + if (pressureVal.val.i16 != _rawPressure) { + pressureVal.val.i16 = _rawPressure; + bool ret; + ret = updateAttributeVal(PressureMeasurement::Id, PressureMeasurement::Attributes::MeasuredValue::Id, &pressureVal); + if (!ret) { + log_e("Failed to update Pressure Sensor Measurement Attribute."); + return false; + } + rawPressure = _rawPressure; + } + log_v("Pressure Sensor set to %.02f Degrees", (float)_rawPressure / 100.00); + + return true; +} + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterPressureSensor.h b/libraries/Matter/src/MatterEndpoints/MatterPressureSensor.h new file mode 100644 index 00000000000..0715c05609d --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterPressureSensor.h @@ -0,0 +1,63 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterPressureSensor : public MatterEndPoint { +public: + MatterPressureSensor(); + ~MatterPressureSensor(); + // begin Matter Pressure Sensor endpoint with initial float pressure + bool begin(double pressure = 0.00) { + return begin(static_cast(pressure)); + } + // this will stop processing Pressure Sensor Matter events + void end(); + + // set the reported raw pressure in hPa + bool setPressure(double pressure) { + int16_t rawValue = static_cast(pressure); + return setRawPressure(rawValue); + } + // returns the reported float pressure in hPa + double getPressure() { + return (double)rawPressure; + } + + // double conversion operator + void operator=(double pressure) { + setPressure(pressure); + } + // double conversion operator + operator double() { + return (double)getPressure(); + } + + // 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); + +protected: + bool started = false; + // implementation keeps pressure in hPa + int16_t rawPressure = 0; + // internal function to set the raw pressure value (Matter Cluster) + bool setRawPressure(int16_t _rawPressure); + bool begin(int16_t _rawPressure); +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterTemperatureSensor.cpp b/libraries/Matter/src/MatterEndpoints/MatterTemperatureSensor.cpp new file mode 100644 index 00000000000..903e6b98d98 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterTemperatureSensor.cpp @@ -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. + +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +bool MatterTemperatureSensor::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_e("Matter Temperature Sensor device has not begun."); + return false; + } + + log_d("Temperature Sensor Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + return ret; +} + +MatterTemperatureSensor::MatterTemperatureSensor() {} + +MatterTemperatureSensor::~MatterTemperatureSensor() { + end(); +} + +bool MatterTemperatureSensor::begin(int16_t _rawTemperature) { + ArduinoMatter::_init(); + + if (getEndPointId() != 0) { + log_e("Temperature Sensor with Endpoint Id %d device has already been created.", getEndPointId()); + return false; + } + + temperature_sensor::config_t temperature_sensor_config; + temperature_sensor_config.temperature_measurement.measured_value = _rawTemperature; + temperature_sensor_config.temperature_measurement.min_measured_value = nullptr; + temperature_sensor_config.temperature_measurement.max_measured_value = nullptr; + + // endpoint handles can be used to add/modify clusters + endpoint_t *endpoint = temperature_sensor::create(node::get(), &temperature_sensor_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Temperature Sensor endpoint"); + return false; + } + rawTemperature = _rawTemperature; + setEndPointId(endpoint::get_id(endpoint)); + log_i("Temperature Sensor created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterTemperatureSensor::end() { + started = false; +} + +bool MatterTemperatureSensor::setRawTemperature(int16_t _rawTemperature) { + if (!started) { + log_e("Matter Temperature Sensor device has not begun."); + return false; + } + + // avoid processing if there was no change + if (rawTemperature == _rawTemperature) { + return true; + } + + esp_matter_attr_val_t temperatureVal = esp_matter_invalid(NULL); + + if (!getAttributeVal(TemperatureMeasurement::Id, TemperatureMeasurement::Attributes::MeasuredValue::Id, &temperatureVal)) { + log_e("Failed to get Temperature Sensor Attribute."); + return false; + } + if (temperatureVal.val.i16 != _rawTemperature) { + temperatureVal.val.i16 = _rawTemperature; + bool ret; + ret = updateAttributeVal(TemperatureMeasurement::Id, TemperatureMeasurement::Attributes::MeasuredValue::Id, &temperatureVal); + if (!ret) { + log_e("Failed to update Temperature Sensor Attribute."); + return false; + } + rawTemperature = _rawTemperature; + } + log_v("Temperature Sensor set to %.02f Degrees", (float)_rawTemperature / 100.00); + + return true; +} + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterTemperatureSensor.h b/libraries/Matter/src/MatterEndpoints/MatterTemperatureSensor.h new file mode 100644 index 00000000000..27c61fdb978 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterTemperatureSensor.h @@ -0,0 +1,64 @@ +// 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 +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterTemperatureSensor : public MatterEndPoint { +public: + MatterTemperatureSensor(); + ~MatterTemperatureSensor(); + // begin Matter Temperature Sensor endpoint with initial float temperature + bool begin(double temperature = 0.00) { + return begin(static_cast(temperature * 100.0f)); + } + // this will stop processing Temperature Sensor Matter events + void end(); + + // set the reported raw temperature + bool setTemperature(double temperature) { + // stores up to 1/100th of a degree precision + int16_t rawValue = static_cast(temperature * 100.0f); + return setRawTemperature(rawValue); + } + // returns the reported float temperature with 1/100th of a degree precision + double getTemperature() { + return (double)rawTemperature / 100.0; + } + + // double conversion operator + void operator=(double temperature) { + setTemperature(temperature); + } + // double conversion operator + operator double() { + return (double)getTemperature(); + } + + // 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); + +protected: + bool started = false; + // implementation keeps temperature in 1/100th of a degree, any temperature unit + int16_t rawTemperature = 0; + // internal function to set the raw temperature value (Matter Cluster) + bool setRawTemperature(int16_t _rawTemperature); + bool begin(int16_t _rawTemperature); +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/NetBIOS/library.properties b/libraries/NetBIOS/library.properties index c073252d6f2..42555781f75 100644 --- a/libraries/NetBIOS/library.properties +++ b/libraries/NetBIOS/library.properties @@ -1,5 +1,5 @@ name=NetBIOS -version=3.0.5 +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 2a80ad844ea..8a1567e68a9 100644 --- a/libraries/Network/library.properties +++ b/libraries/Network/library.properties @@ -1,5 +1,5 @@ name=Networking -version=3.0.5 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=General network management library. diff --git a/libraries/Network/src/NetworkClient.cpp b/libraries/Network/src/NetworkClient.cpp index 067d288bf93..da83597d2c6 100644 --- a/libraries/Network/src/NetworkClient.cpp +++ b/libraries/Network/src/NetworkClient.cpp @@ -210,6 +210,7 @@ int NetworkClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms) { _timeout = timeout_ms; int sockfd = -1; +#if CONFIG_LWIP_IPV6 if (ip.type() == IPv6) { struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr; sockfd = socket(AF_INET6, SOCK_STREAM, 0); @@ -218,12 +219,15 @@ int NetworkClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms) { tmpaddr->sin6_port = htons(port); tmpaddr->sin6_scope_id = ip.zone(); } else { +#endif struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr; sockfd = socket(AF_INET, SOCK_STREAM, 0); tmpaddr->sin_family = AF_INET; tmpaddr->sin_addr.s_addr = ip; tmpaddr->sin_port = htons(port); +#if CONFIG_LWIP_IPV6 } +#endif if (sockfd < 0) { log_e("socket: %d", errno); return 0; @@ -590,6 +594,7 @@ IPAddress NetworkClient::remoteIP(int fd) const { return IPAddress((uint32_t)(s->sin_addr.s_addr)); } +#if CONFIG_LWIP_IPV6 // IPv6, but it might be IPv4 mapped address if (((struct sockaddr *)&addr)->sa_family == AF_INET6) { struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr; @@ -600,6 +605,7 @@ IPAddress NetworkClient::remoteIP(int fd) const { } } log_e("NetworkClient::remoteIP Not AF_INET or AF_INET6?"); +#endif return (IPAddress(0, 0, 0, 0)); } @@ -630,6 +636,7 @@ IPAddress NetworkClient::localIP(int fd) const { return IPAddress((uint32_t)(s->sin_addr.s_addr)); } +#if CONFIG_LWIP_IPV6 // IPv6, but it might be IPv4 mapped address if (((struct sockaddr *)&addr)->sa_family == AF_INET6) { struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr; @@ -640,6 +647,7 @@ IPAddress NetworkClient::localIP(int fd) const { } } log_e("NetworkClient::localIP Not AF_INET or AF_INET6?"); +#endif return (IPAddress(0, 0, 0, 0)); } diff --git a/libraries/Network/src/NetworkClient.h b/libraries/Network/src/NetworkClient.h index 13abf32f934..1baf8b36139 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/Network/src/NetworkEvents.cpp b/libraries/Network/src/NetworkEvents.cpp index 5a7e7c49afa..1a7177bae61 100644 --- a/libraries/Network/src/NetworkEvents.cpp +++ b/libraries/Network/src/NetworkEvents.cpp @@ -368,7 +368,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 e134d6816a2..34a54cab092 100644 --- a/libraries/Network/src/NetworkEvents.h +++ b/libraries/Network/src/NetworkEvents.h @@ -5,11 +5,14 @@ */ #pragma once +#include "sdkconfig.h" #include "soc/soc_caps.h" #include "esp_err.h" #include "esp_event.h" #include "esp_netif_types.h" +#if CONFIG_ETH_ENABLED #include "esp_eth_driver.h" +#endif #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -20,13 +23,15 @@ #include #endif // defined NETWORK_EVENTS_MUTEX && SOC_CPU_CORES_NUM > 1 -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED #include "esp_wifi_types.h" #include "esp_smartconfig.h" +#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI #include "network_provisioning/network_config.h" #endif +#endif -#if SOC_WIFI_SUPPORTED +#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED constexpr int WIFI_SCANNING_BIT = BIT0; constexpr int WIFI_SCAN_DONE_BIT = BIT1; #endif @@ -44,7 +49,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 = 100, ARDUINO_EVENT_WIFI_READY, ARDUINO_EVENT_WIFI_SCAN_DONE, @@ -95,8 +100,10 @@ typedef union { ip_event_ap_staipassigned_t wifi_ap_staipassigned; ip_event_got_ip_t got_ip; ip_event_got_ip6_t got_ip6; +#if CONFIG_ETH_ENABLED esp_eth_handle_t eth_connected; -#if SOC_WIFI_SUPPORTED +#endif +#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; @@ -107,8 +114,12 @@ 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; +#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI network_prov_wifi_sta_fail_reason_t prov_fail_reason; +#endif smartconfig_event_got_ssid_pswd_t sc_got_ssid_pswd; #endif } arduino_event_info_t; @@ -237,7 +248,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/NetworkInterface.cpp b/libraries/Network/src/NetworkInterface.cpp index f4bb1d48392..4f310821204 100644 --- a/libraries/Network/src/NetworkInterface.cpp +++ b/libraries/Network/src/NetworkInterface.cpp @@ -106,6 +106,7 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void *event_data) { } else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) { arduino_event.event_id = ARDUINO_EVENT_ETH_LOST_IP; } +#if CONFIG_LWIP_IPV6 } else if (event_id == IP_EVENT_GOT_IP6) { ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data; esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip); @@ -115,14 +116,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)); @@ -138,6 +135,7 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void *event_data) { } else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) { arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP6; } +#endif /* CONFIG_LWIP_IPV6 */ #if SOC_WIFI_SUPPORTED } else if (event_id == IP_EVENT_AP_STAIPASSIGNED && _interface_id == ESP_NETIF_ID_AP) { setStatusBits(ESP_NETIF_HAS_IP_BIT); @@ -330,6 +328,7 @@ bool NetworkInterface::hasGlobalIPv6() const { } bool NetworkInterface::enableIPv6(bool en) { +#if CONFIG_LWIP_IPV6 if (en) { setStatusBits(ESP_NETIF_WANT_IP6_BIT); if (_esp_netif != NULL && connected()) { @@ -345,6 +344,9 @@ bool NetworkInterface::enableIPv6(bool en) { clearStatusBits(ESP_NETIF_WANT_IP6_BIT); } return true; +#else + return false; +#endif } bool NetworkInterface::dnsIP(uint8_t dns_no, IPAddress ip) { @@ -743,6 +745,7 @@ uint8_t NetworkInterface::subnetCIDR() const { return calculateSubnetCIDR(IPAddress(ip.netmask.addr)); } +#if CONFIG_LWIP_IPV6 IPAddress NetworkInterface::linkLocalIPv6() const { if (_esp_netif == NULL) { return IPAddress(IPv6); @@ -764,6 +767,7 @@ IPAddress NetworkInterface::globalIPv6() const { } return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone); } +#endif size_t NetworkInterface::printTo(Print &out) const { size_t bytes = 0; @@ -838,6 +842,7 @@ size_t NetworkInterface::printTo(Print &out) const { bytes += out.print(dnsIP()); bytes += out.println(); +#if CONFIG_LWIP_IPV6 static const char *types[] = {"UNKNOWN", "GLOBAL", "LINK_LOCAL", "SITE_LOCAL", "UNIQUE_LOCAL", "IPV4_MAPPED_IPV6"}; esp_ip6_addr_t if_ip6[CONFIG_LWIP_IPV6_NUM_ADDRESSES]; int v6addrs = esp_netif_get_all_ip6(_esp_netif, if_ip6); @@ -849,6 +854,7 @@ size_t NetworkInterface::printTo(Print &out) const { bytes += out.print(types[esp_netif_ip6_get_addr_type(&if_ip6[i])]); bytes += out.println(); } +#endif return bytes; } diff --git a/libraries/Network/src/NetworkInterface.h b/libraries/Network/src/NetworkInterface.h index 323cf3bfc72..4f97181d4fd 100644 --- a/libraries/Network/src/NetworkInterface.h +++ b/libraries/Network/src/NetworkInterface.h @@ -70,8 +70,10 @@ class NetworkInterface : public Printable { IPAddress broadcastIP() const; IPAddress networkID() const; uint8_t subnetCIDR() const; +#if CONFIG_LWIP_IPV6 IPAddress linkLocalIPv6() const; IPAddress globalIPv6() const; +#endif size_t printTo(Print &out) const; diff --git a/libraries/Network/src/NetworkManager.cpp b/libraries/Network/src/NetworkManager.cpp index 88059a60562..12276b2e242 100644 --- a/libraries/Network/src/NetworkManager.cpp +++ b/libraries/Network/src/NetworkManager.cpp @@ -87,6 +87,7 @@ int NetworkManager::hostByName(const char *aHostname, IPAddress &aResult) { memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; +#if CONFIG_LWIP_IPV6 // **Workaround** // LWIP AF_UNSPEC always prefers IPv4 and doesn't check what network is // available. See https://github.com/espressif/esp-idf/issues/13255 @@ -106,22 +107,27 @@ int NetworkManager::hostByName(const char *aHostname, IPAddress &aResult) { } } // **End Workaround** +#endif hints.ai_family = AF_UNSPEC; err = lwip_getaddrinfo(aHostname, servname, &hints, &res); if (err == ERR_OK) { +#if CONFIG_LWIP_IPV6 if (res->ai_family == AF_INET6) { struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr; // As an array of u8_t aResult = IPAddress(IPv6, ipv6->sin6_addr.s6_addr); log_d("DNS found IPv6 %s", aResult.toString().c_str()); } else { +#endif struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr; // As a single u32_t aResult = IPAddress(ipv4->sin_addr.s_addr); log_d("DNS found IPv4 %s", aResult.toString().c_str()); +#if CONFIG_LWIP_IPV6 } +#endif lwip_freeaddrinfo(res); return 1; diff --git a/libraries/Network/src/NetworkServer.cpp b/libraries/Network/src/NetworkServer.cpp index 4609757255e..ce8ef952ea7 100644 --- a/libraries/Network/src/NetworkServer.cpp +++ b/libraries/Network/src/NetworkServer.cpp @@ -46,8 +46,13 @@ NetworkClient NetworkServer::accept() { client_sock = _accepted_sockfd; _accepted_sockfd = -1; } else { +#if CONFIG_LWIP_IPV6 struct sockaddr_in6 _client; int cs = sizeof(struct sockaddr_in6); +#else + struct sockaddr_in _client; + int cs = sizeof(struct sockaddr_in); +#endif #ifdef ESP_IDF_VERSION_MAJOR client_sock = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t *)&cs); #else @@ -77,6 +82,7 @@ void NetworkServer::begin(uint16_t port, int enable) { if (port) { _port = port; } +#if CONFIG_LWIP_IPV6 struct sockaddr_in6 server; sockfd = socket(AF_INET6, SOCK_STREAM, 0); if (sockfd < 0) { @@ -93,6 +99,18 @@ void NetworkServer::begin(uint16_t port, int enable) { } memset(server.sin6_addr.s6_addr, 0x0, 16); server.sin6_port = htons(_port); +#else + struct sockaddr_in server; + memset(&server, 0x0, sizeof(sockaddr_in)); + server.sin_family = AF_INET; + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + return; + } + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); + memcpy((uint8_t *)&(server.sin_addr.s_addr), (uint8_t *)&_addr[0], 4); + server.sin_port = htons(_port); +#endif if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { return; } @@ -117,8 +135,13 @@ bool NetworkServer::hasClient() { if (_accepted_sockfd >= 0) { return true; } +#if CONFIG_LWIP_IPV6 struct sockaddr_in6 _client; int cs = sizeof(struct sockaddr_in6); +#else + struct sockaddr _client; + int cs = sizeof(struct sockaddr); +#endif #ifdef ESP_IDF_VERSION_MAJOR _accepted_sockfd = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t *)&cs); #else diff --git a/libraries/Network/src/NetworkUdp.cpp b/libraries/Network/src/NetworkUdp.cpp index 73e0607c5ff..51579910ded 100644 --- a/libraries/Network/src/NetworkUdp.cpp +++ b/libraries/Network/src/NetworkUdp.cpp @@ -255,6 +255,7 @@ int NetworkUDP::endPacket() { log_e("could not send data: %d", errno); return 0; } +#if LWIP_IPV6 } else { struct sockaddr_in6 recipient; recipient.sin6_flowinfo = 0; @@ -267,6 +268,7 @@ int NetworkUDP::endPacket() { log_e("could not send data: %d", errno); return 0; } +#endif } return 1; } @@ -336,12 +338,16 @@ int NetworkUDP::parsePacket() { remote_ip.from_ip_addr_t(&addr); } remote_port = ntohs(si_other.sin6_port); + } else { + remote_ip = ip_addr_any.u_addr.ip4.addr; + remote_port = 0; } -#endif // LWIP_IPV6=1 +#else else { - remote_ip = ip_addr_any.u_addr.ip4.addr; + remote_ip = ip_addr_any.addr; remote_port = 0; } +#endif // LWIP_IPV6=1 if (len > 0) { rx_buffer = new (std::nothrow) cbuf(len); rx_buffer->write(buf, len); diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json index 618e46bd244..cbdd28f773d 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_any": [ "CONFIG_SOC_WIFI_SUPPORTED=y", "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino index a7149e05e6e..b9e01d15682 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino @@ -13,6 +13,11 @@ // Note: this example is outdated and may not work! // For more examples see https://github.com/martinius96/ESP32-eduroam +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#error "WPA-Enterprise is only supported in SoCs with native Wi-Fi support" +#endif + #include #include #if __has_include("esp_eap_client.h") diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json index 618e46bd244..04eb62b977a 100644 --- a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json +++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json @@ -1,6 +1,6 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" ] } diff --git a/libraries/NetworkClientSecure/library.properties b/libraries/NetworkClientSecure/library.properties index f71bc7ef0d8..d810e852524 100644 --- a/libraries/NetworkClientSecure/library.properties +++ b/libraries/NetworkClientSecure/library.properties @@ -1,5 +1,5 @@ name=NetworkClientSecure -version=3.0.5 +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/NetworkClientSecure/src/ssl_client.cpp b/libraries/NetworkClientSecure/src/ssl_client.cpp index 0f93f5cd7fe..19f75673133 100644 --- a/libraries/NetworkClientSecure/src/ssl_client.cpp +++ b/libraries/NetworkClientSecure/src/ssl_client.cpp @@ -83,6 +83,7 @@ int start_ssl_client( fcntl(ssl_client->socket, F_SETFL, fcntl(ssl_client->socket, F_GETFL, 0) | O_NONBLOCK); struct sockaddr_storage serv_addr = {}; +#if CONFIG_LWIP_IPV6 if (domain == AF_INET6) { struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serv_addr; tmpaddr->sin6_family = AF_INET6; @@ -92,11 +93,14 @@ int start_ssl_client( tmpaddr->sin6_port = htons(port); tmpaddr->sin6_scope_id = ip.zone(); } else { +#endif struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serv_addr; tmpaddr->sin_family = AF_INET; tmpaddr->sin_addr.s_addr = ip; tmpaddr->sin_port = htons(port); +#if CONFIG_LWIP_IPV6 } +#endif if (timeout <= 0) { timeout = 30000; // Milli seconds. diff --git a/libraries/OpenThread/library.properties b/libraries/OpenThread/library.properties index 39c6329725e..19d37749a92 100644 --- a/libraries/OpenThread/library.properties +++ b/libraries/OpenThread/library.properties @@ -1,5 +1,5 @@ name=OpenThread -version=3.0.5 +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 47264f1fd8c..e2b290cc893 100644 --- a/libraries/PPP/library.properties +++ b/libraries/PPP/library.properties @@ -1,5 +1,5 @@ name=PPP -version=3.0.5 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables network connection using GSM Modem. diff --git a/libraries/PPP/src/PPP.cpp b/libraries/PPP/src/PPP.cpp index ba1ca2e4869..77b70d3969c 100644 --- a/libraries/PPP/src/PPP.cpp +++ b/libraries/PPP/src/PPP.cpp @@ -1,12 +1,13 @@ #define ARDUINO_CORE_BUILD #include "PPP.h" -#if CONFIG_LWIP_PPP_SUPPORT +#if CONFIG_LWIP_PPP_SUPPORT && ARDUINO_HAS_ESP_MODEM #include "esp32-hal-periman.h" #include "esp_netif.h" #include "esp_netif_ppp.h" #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) { \ @@ -279,7 +280,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 */ @@ -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/PPP/src/PPP.h b/libraries/PPP/src/PPP.h index 52eed57edbc..b8e1f7ad56f 100644 --- a/libraries/PPP/src/PPP.h +++ b/libraries/PPP/src/PPP.h @@ -1,7 +1,11 @@ #pragma once #include "sdkconfig.h" -#if CONFIG_LWIP_PPP_SUPPORT +#if defined __has_include && __has_include("esp_modem_c_api_types.h") +#define ARDUINO_HAS_ESP_MODEM 1 +#endif + +#if CONFIG_LWIP_PPP_SUPPORT && ARDUINO_HAS_ESP_MODEM #include "Network.h" #include "esp_modem_c_api_types.h" @@ -109,5 +113,4 @@ class PPPClass : public NetworkInterface { }; extern PPPClass PPP; - -#endif /* CONFIG_LWIP_PPP_SUPPORT */ +#endif /* CONFIG_LWIP_PPP_SUPPORT && ARDUINO_HAS_ESP_MODEM */ diff --git a/libraries/PPP/src/ppp.c b/libraries/PPP/src/ppp.c index db8ba0760bd..52896e76c8e 100644 --- a/libraries/PPP/src/ppp.c +++ b/libraries/PPP/src/ppp.c @@ -1,5 +1,5 @@ #include "sdkconfig.h" -#if CONFIG_LWIP_PPP_SUPPORT +#if CONFIG_LWIP_PPP_SUPPORT && defined __has_include && __has_include("esp_modem_api.h") #include "esp_modem_api.h" esp_err_t _esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout) { diff --git a/libraries/Preferences/library.properties b/libraries/Preferences/library.properties index 1923e59fc40..90cd20d75c3 100644 --- a/libraries/Preferences/library.properties +++ b/libraries/Preferences/library.properties @@ -1,5 +1,5 @@ name=Preferences -version=3.0.5 +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/examples/RMakerSwitch/RMakerSwitch.ino b/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino index 9c65881889d..21fe9cb064b 100644 --- a/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino +++ b/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino @@ -94,6 +94,12 @@ void setup() { RMaker.enableSystemService(SYSTEM_SERV_FLAGS_ALL, 2, 2, 2); +#if CONFIG_IDF_TARGET_ESP32S2 + WiFiProv.initProvision(NETWORK_PROV_SCHEME_SOFTAP, NETWORK_PROV_SCHEME_HANDLER_NONE); +#else + WiFiProv.initProvision(NETWORK_PROV_SCHEME_BLE, NETWORK_PROV_SCHEME_HANDLER_FREE_BTDM); +#endif + RMaker.start(); WiFi.onEvent(sysProvEvent); // Will call sysProvEvent() from another thread. diff --git a/libraries/RainMaker/library.properties b/libraries/RainMaker/library.properties index cf67e9772e1..0c3e6e26697 100644 --- a/libraries/RainMaker/library.properties +++ b/libraries/RainMaker/library.properties @@ -1,5 +1,5 @@ name=ESP RainMaker -version=3.0.5 +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 ca73443684f..3fd1a3f8a3e 100644 --- a/libraries/SD/library.properties +++ b/libraries/SD/library.properties @@ -1,5 +1,5 @@ name=SD -version=3.0.5 +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/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/library.properties b/libraries/SD_MMC/library.properties index 176947e4017..94586e8e1ec 100644 --- a/libraries/SD_MMC/library.properties +++ b/libraries/SD_MMC/library.properties @@ -1,5 +1,5 @@ name=SD_MMC -version=3.0.5 +version=3.1.0 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 SDMMC File System diff --git a/libraries/SD_MMC/src/SD_MMC.cpp b/libraries/SD_MMC/src/SD_MMC.cpp index 13e5fcf27fc..4665198c4ae 100644 --- a/libraries/SD_MMC/src/SD_MMC.cpp +++ b/libraries/SD_MMC/src/SD_MMC.cpp @@ -32,10 +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(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,7 +49,7 @@ SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) { _pin_d3 = SDMMC_D3; #endif // BOARD_HAS_1BIT_SDMMC -#elif SOC_SDMMC_USE_IOMUX +#elif defined(SOC_SDMMC_USE_IOMUX) && 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 +58,31 @@ 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 + +// 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; +#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 +#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 } @@ -83,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; @@ -104,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; @@ -123,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))) { @@ -163,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; @@ -174,8 +247,40 @@ 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, .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); @@ -236,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/libraries/SPI/library.properties b/libraries/SPI/library.properties index 8d704b2667e..a7a7204db62 100644 --- a/libraries/SPI/library.properties +++ b/libraries/SPI/library.properties @@ -1,5 +1,5 @@ name=SPI -version=3.0.5 +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/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/library.properties b/libraries/SPIFFS/library.properties index a901b32effd..132ff5fb7f1 100644 --- a/libraries/SPIFFS/library.properties +++ b/libraries/SPIFFS/library.properties @@ -1,5 +1,5 @@ name=SPIFFS -version=3.0.5 +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 ab634e30461..ae28a21c0df 100644 --- a/libraries/SimpleBLE/library.properties +++ b/libraries/SimpleBLE/library.properties @@ -1,5 +1,5 @@ name=SimpleBLE -version=3.0.5 +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 026411cd30e..cde7d21bec1 100644 --- a/libraries/TFLiteMicro/library.properties +++ b/libraries/TFLiteMicro/library.properties @@ -1,5 +1,5 @@ name=TFLite Micro -version=3.0.5 +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 3486c45fb09..d6e9829c6ef 100644 --- a/libraries/Ticker/library.properties +++ b/libraries/Ticker/library.properties @@ -1,5 +1,5 @@ name=Ticker -version=3.0.5 +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 abfa263769f..752acf3a803 100644 --- a/libraries/USB/library.properties +++ b/libraries/USB/library.properties @@ -1,5 +1,5 @@ name=USB -version=3.0.5 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=ESP32S2 USB Library diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index 75f37ef5df3..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), 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); diff --git a/libraries/Update/library.properties b/libraries/Update/library.properties index 1aece5b163e..9d480986b1e 100644 --- a/libraries/Update/library.properties +++ b/libraries/Update/library.properties @@ -1,5 +1,5 @@ name=Update -version=3.0.5 +version=3.1.0 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=ESP32 Sketch Update Library diff --git a/libraries/Update/src/Update.h b/libraries/Update/src/Update.h index 5832846fd28..9a4d3e02489 100644 --- a/libraries/Update/src/Update.h +++ b/libraries/Update/src/Update.h @@ -63,6 +63,7 @@ class UpdateClass { */ bool begin(size_t size = UPDATE_SIZE_UNKNOWN, int command = U_FLASH, int ledPin = -1, uint8_t ledOn = LOW, const char *label = NULL); +#ifndef UPDATE_NOCRYPT /* Setup decryption configuration Crypt Key is 32bytes(256bits) block of data, use the same key as used to encrypt image file @@ -71,6 +72,7 @@ class UpdateClass { Crypt Mode, used to select if image files should be decrypted or not */ bool setupCrypt(const uint8_t *cryptKey = 0, size_t cryptAddress = 0, uint8_t cryptConfig = 0xf, int cryptMode = U_AES_DECRYPT_AUTO); +#endif /* UPDATE_NOCRYPT */ /* Writes a buffer to the flash and increments the address @@ -99,6 +101,7 @@ class UpdateClass { */ bool end(bool evenIfRemaining = false); +#ifndef UPDATE_NOCRYPT /* sets AES256 key(32 bytes) used for decrypting image file */ @@ -122,6 +125,7 @@ class UpdateClass { void setCryptConfig(const uint8_t cryptConfig) { _cryptCfg = cryptConfig & 0x0f; } +#endif /* UPDATE_NOCRYPT */ /* Aborts the running update @@ -139,7 +143,13 @@ 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 calc_post_decryption = true); + bool setMD5( + const char *expected_md5 +#ifndef UPDATE_NOCRYPT + , + bool calc_post_decryption = true +#endif /* #ifdef UPDATE_NOCRYPT */ + ); /* returns the MD5 String of the successfully ended firmware @@ -236,8 +246,10 @@ class UpdateClass { private: void _reset(); void _abort(uint8_t err); +#ifndef UPDATE_NOCRYPT void _cryptKeyTweak(size_t cryptAddress, uint8_t *tweaked_key); bool _decryptBuffer(); +#endif /* UPDATE_NOCRYPT */ bool _writeBuffer(); bool _verifyHeader(uint8_t data); bool _verifyEnd(); @@ -245,8 +257,10 @@ class UpdateClass { bool _chkDataInBlock(const uint8_t *data, size_t len) const; // check if block contains any data or is empty uint8_t _error; +#ifndef UPDATE_NOCRYPT uint8_t *_cryptKey; uint8_t *_cryptBuffer; +#endif /* UPDATE_NOCRYPT */ uint8_t *_buffer; uint8_t *_skipBuffer; size_t _bufferLen; @@ -258,15 +272,19 @@ class UpdateClass { const esp_partition_t *_partition; String _target_md5; +#ifndef UPDATE_NOCRYPT bool _target_md5_decrypted = true; +#endif /* UPDATE_NOCRYPT */ MD5Builder _md5; int _ledPin; uint8_t _ledOn; +#ifndef UPDATE_NOCRYPT uint8_t _cryptMode; size_t _cryptAddress; uint8_t _cryptCfg; +#endif /* UPDATE_NOCRYPT */ }; #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_UPDATE) diff --git a/libraries/Update/src/Updater.cpp b/libraries/Update/src/Updater.cpp index e92f84d4599..3b0c517431d 100644 --- a/libraries/Update/src/Updater.cpp +++ b/libraries/Update/src/Updater.cpp @@ -9,7 +9,9 @@ #include "spi_flash_mmap.h" #include "esp_ota_ops.h" #include "esp_image_format.h" +#ifndef UPDATE_NOCRYPT #include "mbedtls/aes.h" +#endif /* UPDATE_NOCRYPT */ static const char *_err2str(uint8_t _error) { if (_error == UPDATE_ERROR_OK) { @@ -38,8 +40,10 @@ static const char *_err2str(uint8_t _error) { return ("Bad Argument"); } else if (_error == UPDATE_ERROR_ABORT) { return ("Aborted"); +#ifndef UPDATE_NOCRYPT } else if (_error == UPDATE_ERROR_DECRYPT) { return ("Decryption error"); +#endif /* UPDATE_NOCRYPT */ } return ("UNKNOWN"); } @@ -67,8 +71,17 @@ bool UpdateClass::_enablePartition(const esp_partition_t *partition) { } UpdateClass::UpdateClass() - : _error(0), _cryptKey(0), _cryptBuffer(0), _buffer(0), _skipBuffer(0), _bufferLen(0), _size(0), _progress_callback(NULL), _progress(0), _paroffset(0), - _command(U_FLASH), _partition(NULL), _cryptMode(U_AES_DECRYPT_AUTO), _cryptAddress(0), _cryptCfg(0xf) {} + : _error(0), +#ifndef UPDATE_NOCRYPT + _cryptKey(0), _cryptBuffer(0), +#endif /* UPDATE_NOCRYPT */ + _buffer(0), _skipBuffer(0), _bufferLen(0), _size(0), _progress_callback(NULL), _progress(0), _paroffset(0), _command(U_FLASH), _partition(NULL) +#ifndef UPDATE_NOCRYPT + , + _cryptMode(U_AES_DECRYPT_AUTO), _cryptAddress(0), _cryptCfg(0xf) +#endif /* UPDATE_NOCRYPT */ +{ +} UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress fn) { _progress_callback = fn; @@ -83,7 +96,9 @@ void UpdateClass::_reset() { delete[] _skipBuffer; } +#ifndef UPDATE_NOCRYPT _cryptBuffer = nullptr; +#endif /* UPDATE_NOCRYPT */ _buffer = nullptr; _skipBuffer = nullptr; _bufferLen = 0; @@ -175,6 +190,7 @@ bool UpdateClass::begin(size_t size, int command, int ledPin, uint8_t ledOn, con return true; } +#ifndef UPDATE_NOCRYPT bool UpdateClass::setupCrypt(const uint8_t *cryptKey, size_t cryptAddress, uint8_t cryptConfig, int cryptMode) { if (setCryptKey(cryptKey)) { if (setCryptMode(cryptMode)) { @@ -216,6 +232,7 @@ bool UpdateClass::setCryptMode(const int cryptMode) { } return true; } +#endif /* UPDATE_NOCRYPT */ void UpdateClass::_abort(uint8_t err) { _reset(); @@ -226,6 +243,7 @@ void UpdateClass::abort() { _abort(UPDATE_ERROR_ABORT); } +#ifndef UPDATE_NOCRYPT void UpdateClass::_cryptKeyTweak(size_t cryptAddress, uint8_t *tweaked_key) { memcpy(tweaked_key, _cryptKey, ENCRYPTED_KEY_SIZE); if (_cryptCfg == 0) { @@ -338,8 +356,10 @@ bool UpdateClass::_decryptBuffer() { } return true; } +#endif /* UPDATE_NOCRYPT */ bool UpdateClass::_writeBuffer() { +#ifndef UPDATE_NOCRYPT //first bytes of loading image, check to see if loading image needs decrypting if (!_progress) { _cryptMode &= U_AES_DECRYPT_MODE_MASK; @@ -360,6 +380,7 @@ bool UpdateClass::_writeBuffer() { return false; } } +#endif /* UPDATE_NOCRYPT */ //first bytes of new firmware uint8_t skip = 0; if (!_progress && _command == U_FLASH) { @@ -409,9 +430,13 @@ bool UpdateClass::_writeBuffer() { if (!_progress && _command == U_FLASH) { _buffer[0] = ESP_IMAGE_HEADER_MAGIC; } +#ifndef UPDATE_NOCRYPT if (_target_md5_decrypted) { +#endif /* UPDATE_NOCRYPT */ _md5.add(_buffer, _bufferLen); +#ifndef UPDATE_NOCRYPT } +#endif /* UPDATE_NOCRYPT */ _progress += _bufferLen; _bufferLen = 0; if (_progress_callback) { @@ -453,13 +478,21 @@ bool UpdateClass::_verifyEnd() { return false; } -bool UpdateClass::setMD5(const char *expected_md5, bool calc_post_decryption) { +bool UpdateClass::setMD5( + const char *expected_md5 +#ifndef UPDATE_NOCRYPT + , + bool calc_post_decryption +#endif /* UPDATE_NOCRYPT */ +) { if (strlen(expected_md5) != 32) { return false; } _target_md5 = expected_md5; _target_md5.toLowerCase(); +#ifndef UPDATE_NOCRYPT _target_md5_decrypted = calc_post_decryption; +#endif /* UPDATE_NOCRYPT */ return true; } @@ -532,12 +565,16 @@ size_t UpdateClass::writeStream(Stream &data) { return 0; } +#ifndef UPDATE_NOCRYPT if (_command == U_FLASH && !_cryptMode) { +#endif /* UPDATE_NOCRYPT */ if (!_verifyHeader(data.peek())) { _reset(); return 0; } +#ifndef UPDATE_NOCRYPT } +#endif /* UPDATE_NOCRYPT */ if (_ledPin != -1) { pinMode(_ledPin, OUTPUT); diff --git a/libraries/WebServer/library.properties b/libraries/WebServer/library.properties index 8985e6f5179..89e35e4713d 100644 --- a/libraries/WebServer/library.properties +++ b/libraries/WebServer/library.properties @@ -1,5 +1,5 @@ name=WebServer -version=3.0.5 +version=3.1.0 author=Ivan Grokhotkov maintainer=Ivan Grokhtkov sentence=Simple web server library diff --git a/libraries/WiFi/examples/WPS/WPS.ino b/libraries/WiFi/examples/WPS/WPS.ino index fc353dcbfb8..aacdd14ddab 100644 --- a/libraries/WiFi/examples/WPS/WPS.ino +++ b/libraries/WiFi/examples/WPS/WPS.ino @@ -14,6 +14,11 @@ Author: Pranav Cherukupalli */ +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#error "WPS is only supported in SoCs with native Wi-Fi support" +#endif + #include "WiFi.h" #include "esp_wps.h" /* diff --git a/libraries/WiFi/examples/WPS/ci.json b/libraries/WiFi/examples/WPS/ci.json index 618e46bd244..36babb82730 100644 --- a/libraries/WiFi/examples/WPS/ci.json +++ b/libraries/WiFi/examples/WPS/ci.json @@ -1,6 +1,5 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" ] } diff --git a/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino b/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino index 75b7a4dcc06..198f97e2805 100644 --- a/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino +++ b/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino @@ -1,3 +1,8 @@ +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#error "WPA-Enterprise is only supported in SoCs with native Wi-Fi support" +#endif + #include //Wifi library #define EAP_IDENTITY "login" //if connecting from another corporation, use identity@organization.domain in Eduroam #define EAP_USERNAME "login" //oftentimes just a repeat of the identity diff --git a/libraries/WiFi/examples/WiFiClientEnterprise/ci.json b/libraries/WiFi/examples/WiFiClientEnterprise/ci.json index 618e46bd244..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiClientEnterprise/ci.json +++ b/libraries/WiFi/examples/WiFiClientEnterprise/ci.json @@ -1,6 +1,5 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" ] } diff --git a/libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino b/libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino index 6d372bb1098..724355c6a37 100644 --- a/libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino +++ b/libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino @@ -1,3 +1,8 @@ +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#error "SmartConfig is only supported in SoCs with native Wi-Fi support" +#endif + #include "WiFi.h" void setup() { diff --git a/libraries/WiFi/examples/WiFiSmartConfig/ci.json b/libraries/WiFi/examples/WiFiSmartConfig/ci.json index 618e46bd244..36babb82730 100644 --- a/libraries/WiFi/examples/WiFiSmartConfig/ci.json +++ b/libraries/WiFi/examples/WiFiSmartConfig/ci.json @@ -1,6 +1,5 @@ { - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" ] } diff --git a/libraries/WiFi/library.properties b/libraries/WiFi/library.properties index fa63459c166..925616ea561 100644 --- a/libraries/WiFi/library.properties +++ b/libraries/WiFi/library.properties @@ -1,5 +1,5 @@ name=WiFi -version=3.0.5 +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/WiFi/src/AP.cpp b/libraries/WiFi/src/AP.cpp index a61be662495..b713a6d3901 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 @@ -87,6 +87,7 @@ static void _onApArduinoEvent(arduino_event_t *ev) { } log_v("Arduino AP Event: %d - %s", ev->event_id, Network.eventName(ev->event_id)); if (ev->event_id == ARDUINO_EVENT_WIFI_AP_START) { +#if CONFIG_LWIP_IPV6 if (_ap_network_if->getStatusBits() & ESP_NETIF_WANT_IP6_BIT) { esp_err_t err = esp_netif_create_ip6_linklocal(_ap_network_if->netif()); if (err != ESP_OK) { @@ -95,6 +96,7 @@ static void _onApArduinoEvent(arduino_event_t *ev) { log_v("Enabled IPv6 Link Local on %s", _ap_network_if->desc()); } } +#endif } } diff --git a/libraries/WiFi/src/STA.cpp b/libraries/WiFi/src/STA.cpp index 443d2621957..547a27d1c47 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 @@ -118,6 +118,7 @@ static void _onStaArduinoEvent(arduino_event_t *ev) { _sta_network_if->_setStatus(WL_STOPPED); } else if (ev->event_id == ARDUINO_EVENT_WIFI_STA_CONNECTED) { _sta_network_if->_setStatus(WL_IDLE_STATUS); +#if CONFIG_LWIP_IPV6 if (_sta_network_if->getStatusBits() & ESP_NETIF_WANT_IP6_BIT) { esp_err_t err = esp_netif_create_ip6_linklocal(_sta_network_if->netif()); if (err != ESP_OK) { @@ -126,6 +127,7 @@ static void _onStaArduinoEvent(arduino_event_t *ev) { log_v("Enabled IPv6 Link Local on %s", _sta_network_if->desc()); } } +#endif } else if (ev->event_id == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) { uint8_t reason = ev->event_info.wifi_sta_disconnected.reason; // Reason 0 causes crash, use reason 1 (UNSPECIFIED) instead @@ -419,6 +421,7 @@ bool STAClass::connect(const char *ssid, const char *passphrase, int32_t channel return true; } +#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT /** * Start Wifi connection with a WPA2 Enterprise AP * if passphrase is set the most secure supported mode will be automatically selected @@ -517,6 +520,7 @@ bool STAClass::connect( return connect(wpa2_ssid, NULL, channel, bssid, tryConnect); //connect to wifi } +#endif /* CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT */ bool STAClass::disconnect(bool eraseap, unsigned long timeout) { if (eraseap) { 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..bb15ff44625 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 @@ -177,6 +177,7 @@ bool WiFiAPClass::softAPsetHostname(const char *hostname) { return AP.setHostname(hostname); } +#if CONFIG_LWIP_IPV6 /** * Enable IPv6 on the softAP interface. * @return true on success @@ -193,5 +194,5 @@ bool WiFiAPClass::softAPenableIPv6(bool enable) { IPAddress WiFiAPClass::softAPlinkLocalIPv6() { return AP.linkLocalIPv6(); } - +#endif #endif /* SOC_WIFI_SUPPORTED */ diff --git a/libraries/WiFi/src/WiFiAP.h b/libraries/WiFi/src/WiFiAP.h index 9acd124c27e..e80f91fa26c 100644 --- a/libraries/WiFi/src/WiFiAP.h +++ b/libraries/WiFi/src/WiFiAP.h @@ -23,7 +23,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 "esp_wifi_types.h" #include "WiFiType.h" @@ -100,8 +101,10 @@ class WiFiAPClass { IPAddress softAPSubnetMask(); uint8_t softAPSubnetCIDR(); +#if CONFIG_LWIP_IPV6 bool softAPenableIPv6(bool enable = true); IPAddress softAPlinkLocalIPv6(); +#endif const char *softAPgetHostname(); bool softAPsetHostname(const char *hostname); diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index 6ddf384d009..40e3b12c687 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,6 +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" @@ -102,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 * */ @@ -123,6 +127,7 @@ static void _arduino_event_cb(void *arg, esp_event_base_t event_base, int32_t ev log_v("SC Send Ack Done"); arduino_event.event_id = ARDUINO_EVENT_SC_SEND_ACK_DONE; +#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI /* * Provisioning * */ @@ -156,6 +161,8 @@ 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 +#endif } if (arduino_event.event_id < ARDUINO_EVENT_MAX) { @@ -169,15 +176,19 @@ 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; } +#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI if (esp_event_handler_instance_register(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb, NULL, NULL)) { log_e("event_handler_instance_register for NETWORK_PROV_EVENT Failed!"); return false; } +#endif +#endif return true; } @@ -188,15 +199,19 @@ 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; } +#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI if (esp_event_handler_unregister(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb)) { log_e("esp_event_handler_unregister for NETWORK_PROV_EVENT Failed!"); return false; } +#endif +#endif return true; } @@ -224,9 +239,57 @@ void WiFiGenericClass::useStaticBuffers(bool bufferMode) { extern "C" void phy_bbpll_en_usb(bool en); #endif +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +extern "C" { +//#include "esp_hosted.h" +#include "esp_hosted_transport_config.h" +extern esp_err_t esp_hosted_init(); +extern esp_err_t esp_hosted_deinit(); +}; +static bool hosted_initialized = false; + +static bool wifiHostedInit() { + if (!hosted_initialized) { + hosted_initialized = true; + struct esp_hosted_sdio_config conf = INIT_DEFAULT_HOST_SDIO_CONFIG(); + conf.pin_clk.pin = CONFIG_ESP_SDIO_PIN_CLK; + conf.pin_cmd.pin = CONFIG_ESP_SDIO_PIN_CMD; + conf.pin_d0.pin = CONFIG_ESP_SDIO_PIN_D0; + conf.pin_d1.pin = CONFIG_ESP_SDIO_PIN_D1; + conf.pin_d2.pin = CONFIG_ESP_SDIO_PIN_D2; + conf.pin_d3.pin = CONFIG_ESP_SDIO_PIN_D3; + //conf.pin_rst.pin = CONFIG_ESP_SDIO_GPIO_RESET_SLAVE; + // esp_hosted_sdio_set_config() will fail on second attempt but here temporarily to not cause exception on reinit + if (esp_hosted_sdio_set_config(&conf) != ESP_OK || esp_hosted_init() != ESP_OK) { + log_e("esp_hosted_init failed!"); + hosted_initialized = false; + return false; + } + log_v("ESP-HOSTED initialized!"); + } + // 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; @@ -290,6 +353,13 @@ static bool wifiLowLevelDeinit() { arduino_event_t arduino_event; arduino_event.event_id = ARDUINO_EVENT_WIFI_OFF; Network.postEvent(&arduino_event); +#if CONFIG_ESP_WIFI_REMOTE_ENABLED + if (hosted_initialized && esp_hosted_deinit() == ESP_OK) { + hosted_initialized = false; + log_v("ESP-HOSTED uninitialized!"); + // detach SDIO pins from PeriMan + } +#endif } } return !lowLevelInitDone; @@ -369,6 +439,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, @@ -377,6 +448,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 } } @@ -692,10 +764,11 @@ 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 - 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,60 +778,60 @@ 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; } - +#endif return true; } diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h index 2a5ca812999..ed216229ed4 100644 --- a/libraries/WiFi/src/WiFiGeneric.h +++ b/libraries/WiFi/src/WiFiGeneric.h @@ -23,7 +23,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 "esp_err.h" #include "esp_event.h" @@ -32,8 +33,12 @@ #include "IPAddress.h" #include "esp_smartconfig.h" #include "esp_netif_types.h" +#if CONFIG_ETH_ENABLED #include "esp_eth_driver.h" +#endif +#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI #include "network_provisioning/manager.h" +#endif #include "lwip/ip_addr.h" #include "Network.h" diff --git a/libraries/WiFi/src/WiFiMulti.cpp b/libraries/WiFi/src/WiFiMulti.cpp index a438919f792..c99bef5ac90 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 @@ -251,9 +251,11 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout, bool scanHidden) { bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb ); +#if CONFIG_LWIP_IPV6 if (ipv6_support == true) { WiFi.enableIPv6(); } +#endif WiFi.disconnect(); delay(10); WiFi.begin(bestNetwork.ssid, (_bAllowOpenAP && bestNetworkSec == WIFI_AUTH_OPEN) ? NULL : bestNetwork.passphrase, bestChannel, bestBSSID); @@ -318,9 +320,11 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout, bool scanHidden) { return status; } +#if CONFIG_LWIP_IPV6 void WiFiMulti::enableIPv6(bool state) { ipv6_support = state; } +#endif void WiFiMulti::markAsFailed(int32_t i) { APlist[i].hasFailed = true; diff --git a/libraries/WiFi/src/WiFiMulti.h b/libraries/WiFi/src/WiFiMulti.h index 1e11ff13f51..d818f77899f 100644 --- a/libraries/WiFi/src/WiFiMulti.h +++ b/libraries/WiFi/src/WiFiMulti.h @@ -26,7 +26,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 "WiFi.h" #include @@ -46,7 +47,9 @@ class WiFiMulti { bool addAP(const char *ssid, const char *passphrase = NULL); uint8_t run(uint32_t connectTimeout = 5000, bool scanHidden = false); +#if CONFIG_LWIP_IPV6 void enableIPv6(bool state); +#endif // Force (default: true) to only keep connected or to connect to an AP from the provided WiFiMulti list. // When bStrict is false, it will keep the last/current connected AP even if not in the WiFiMulti List. diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp index 99c02a4b81d..b956e35ba26 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 @@ -63,6 +63,7 @@ wl_status_t WiFiSTAClass::status() { return STA.status(); } +#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT wl_status_t WiFiSTAClass::begin( const char *wpa2_ssid, wpa2_auth_method_t method, const char *wpa2_identity, const char *wpa2_username, const char *wpa2_password, const char *ca_pem, const char *client_crt, const char *client_key, int ttls_phase2_type, int32_t channel, const uint8_t *bssid, bool connect @@ -77,6 +78,7 @@ wl_status_t WiFiSTAClass::begin( return STA.status(); } +#endif /* CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT */ wl_status_t WiFiSTAClass::begin(const char *ssid, const char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) { if (!STA.begin()) { @@ -386,6 +388,7 @@ int8_t WiFiSTAClass::RSSI(void) { return STA.RSSI(); } +#if CONFIG_LWIP_IPV6 /** * Enable IPv6 on the station interface. * Should be called before WiFi.begin() @@ -411,6 +414,7 @@ IPAddress WiFiSTAClass::linkLocalIPv6() { IPAddress WiFiSTAClass::globalIPv6() { return STA.globalIPv6(); } +#endif bool WiFiSTAClass::_smartConfigStarted = false; bool WiFiSTAClass::_smartConfigDone = false; diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index 2c046c4c4b9..3c8adbd8502 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -23,7 +23,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 "WiFiType.h" #include "WiFiGeneric.h" @@ -53,11 +54,13 @@ class STAClass : public NetworkInterface { bool connect(); bool connect(const char *ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true); +#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT bool connect( const char *wpa2_ssid, wpa2_auth_method_t method, const char *wpa2_identity = NULL, const char *wpa2_username = NULL, const char *wpa2_password = NULL, const char *ca_pem = NULL, const char *client_crt = NULL, const char *client_key = NULL, int ttls_phase2_type = -1, int32_t channel = 0, const uint8_t *bssid = 0, bool connect = true ); +#endif /* CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT */ bool disconnect(bool eraseap = false, unsigned long timeout = 0); bool reconnect(); bool erase(); @@ -108,6 +111,7 @@ class WiFiSTAClass { public: STAClass STA; +#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT wl_status_t begin( const char *wpa2_ssid, wpa2_auth_method_t method, const char *wpa2_identity = NULL, const char *wpa2_username = NULL, const char *wpa2_password = NULL, const char *ca_pem = NULL, const char *client_crt = NULL, const char *client_key = NULL, int ttls_phase2_type = -1, int32_t channel = 0, @@ -123,6 +127,8 @@ class WiFiSTAClass { ttls_phase2_type, channel, bssid, connect ); } +#endif /* CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT */ + wl_status_t begin(const char *ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true); wl_status_t begin(const String &ssid, const String &passphrase = (const char *)NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true) { return begin(ssid.c_str(), passphrase.c_str(), channel, bssid, connect); @@ -179,9 +185,11 @@ class WiFiSTAClass { IPAddress networkID(); uint8_t subnetCIDR(); +#if CONFIG_LWIP_IPV6 bool enableIPv6(bool en = true); IPAddress linkLocalIPv6(); IPAddress globalIPv6(); +#endif // ---------------------------------------------------------------------------------------------- // ---------------------------------------- Smart Config ---------------------------------------- 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..7afd26bb76a 100644 --- a/libraries/WiFi/src/WiFiScan.h +++ b/libraries/WiFi/src/WiFiScan.h @@ -23,7 +23,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 "WiFiType.h" #include "WiFiGeneric.h" diff --git a/libraries/WiFi/src/WiFiType.h b/libraries/WiFi/src/WiFiType.h index 1d721d33963..29af9ce2252 100644 --- a/libraries/WiFi/src/WiFiType.h +++ b/libraries/WiFi/src/WiFiType.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 "esp_wifi_types.h" diff --git a/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino b/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino index 59b8bfc359e..76025d75770 100644 --- a/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino +++ b/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino @@ -8,6 +8,11 @@ Note: This sketch takes up a lot of space for the app and may not be able to fla - for example "No OTA (2MB APP/2MB SPIFFS)" */ +#include "sdkconfig.h" +#if CONFIG_ESP_WIFI_REMOTE_ENABLED +#error "WiFiProv is only supported in SoCs with native Wi-Fi support" +#endif + #include "WiFiProv.h" #include "WiFi.h" diff --git a/libraries/WiFiProv/examples/WiFiProv/ci.json b/libraries/WiFiProv/examples/WiFiProv/ci.json index cbdd28f773d..04eb62b977a 100644 --- a/libraries/WiFiProv/examples/WiFiProv/ci.json +++ b/libraries/WiFiProv/examples/WiFiProv/ci.json @@ -1,7 +1,6 @@ { "fqbn_append": "PartitionScheme=huge_app", - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" ] } diff --git a/libraries/WiFiProv/library.properties b/libraries/WiFiProv/library.properties index cbba5a3fbeb..20e27fc5097 100644 --- a/libraries/WiFiProv/library.properties +++ b/libraries/WiFiProv/library.properties @@ -1,5 +1,5 @@ name=WiFiProv -version=3.0.5 +version=3.1.0 author=Switi Mhaiske maintainer=Hristo Gochkov sentence=Enables provisioning. diff --git a/libraries/WiFiProv/src/WiFiProv.cpp b/libraries/WiFiProv/src/WiFiProv.cpp index f4008d44ded..31337196b5f 100644 --- a/libraries/WiFiProv/src/WiFiProv.cpp +++ b/libraries/WiFiProv/src/WiFiProv.cpp @@ -18,7 +18,8 @@ */ #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#include "sdkconfig.h" +#if SOC_WIFI_SUPPORTED && CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI #include #include @@ -71,13 +72,11 @@ static void get_device_service_name(prov_scheme_t prov_scheme, char *service_nam #endif } -void WiFiProvClass ::beginProvision( - prov_scheme_t prov_scheme, scheme_handler_t scheme_handler, network_prov_security_t security, const char *pop, const char *service_name, - const char *service_key, uint8_t *uuid, bool reset_provisioned -) { - bool provisioned = false; - static char service_name_temp[32]; - +void WiFiProvClass ::initProvision(prov_scheme_t prov_scheme, scheme_handler_t scheme_handler, bool reset_provisioned) { + if (this->provInitDone) { + log_i("provInit was already done!"); + return; + } network_prov_mgr_config_t config; #if CONFIG_BLUEDROID_ENABLED if (prov_scheme == NETWORK_PROV_SCHEME_BLE) { @@ -117,11 +116,22 @@ void WiFiProvClass ::beginProvision( if (reset_provisioned) { log_i("Resetting provisioned data."); network_prov_mgr_reset_wifi_provisioning(); - } else if (network_prov_mgr_is_wifi_provisioned(&provisioned) != ESP_OK) { + } else if (network_prov_mgr_is_wifi_provisioned(&(this->provisioned)) != ESP_OK) { log_e("network_prov_mgr_is_wifi_provisioned failed!"); network_prov_mgr_deinit(); return; } + this->provInitDone = true; +} + +void WiFiProvClass ::beginProvision( + prov_scheme_t prov_scheme, scheme_handler_t scheme_handler, network_prov_security_t security, const char *pop, const char *service_name, + const char *service_key, uint8_t *uuid, bool reset_provisioned +) { + if (!this->provInitDone) { + WiFiProvClass ::initProvision(prov_scheme, scheme_handler, reset_provisioned); + } + static char service_name_temp[32]; if (provisioned == false) { #if CONFIG_BLUEDROID_ENABLED if (prov_scheme == NETWORK_PROV_SCHEME_BLE) { diff --git a/libraries/WiFiProv/src/WiFiProv.h b/libraries/WiFiProv/src/WiFiProv.h index 44dda82ad0e..b660f8cf064 100644 --- a/libraries/WiFiProv/src/WiFiProv.h +++ b/libraries/WiFiProv/src/WiFiProv.h @@ -20,7 +20,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_WIFI_SUPPORTED +#include "sdkconfig.h" +#if SOC_WIFI_SUPPORTED && CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI #include "WiFi.h" #include "HardwareSerial.h" @@ -46,7 +47,14 @@ typedef enum { //Provisioning class class WiFiProvClass { +private: + bool provInitDone = false; + bool provisioned = false; + public: + void initProvision( + prov_scheme_t prov_scheme = NETWORK_PROV_SCHEME_SOFTAP, scheme_handler_t scheme_handler = NETWORK_PROV_SCHEME_HANDLER_NONE, bool reset_provisioned = false + ); void beginProvision( prov_scheme_t prov_scheme = NETWORK_PROV_SCHEME_SOFTAP, scheme_handler_t scheme_handler = NETWORK_PROV_SCHEME_HANDLER_NONE, network_prov_security_t security = NETWORK_PROV_SECURITY_1, const char *pop = "abcd1234", const char *service_name = NULL, const char *service_key = NULL, diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties index 2d4ef887e34..a2d79eee81b 100644 --- a/libraries/Wire/library.properties +++ b/libraries/Wire/library.properties @@ -1,5 +1,5 @@ name=Wire -version=3.0.5 +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/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 */ diff --git a/libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/README.md new file mode 100644 index 00000000000..88c8bf04a65 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/README.md @@ -0,0 +1,72 @@ +# Arduino-ESP32 Carbon dioxide (CO2) Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) simple sensor device type with carbon dioxide measuring. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Pressure + Flow Sensor Functions + + * After this board first starts up, it would be configured locally to report the carbon dioxide on every 30 seconds. + * By clicking the button (BOOT) on this board, this board will immediately send a report of the current measured carbon dioxide to the network. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +In this example, the internal temperature sensor is used to demonstrate reading of the carbon dioxide sensors. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (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 + +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_CarbonDioxide_Sensor/Zigbee_CarbonDioxide_Sensor.ino b/libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/Zigbee_CarbonDioxide_Sensor.ino new file mode 100644 index 00000000000..47b9a05493f --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/Zigbee_CarbonDioxide_Sensor.ino @@ -0,0 +1,106 @@ +// 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 carbon dioxide sensor. + * + * The example demonstrates how to use Zigbee library to create a end device carbon dioxide sensor. + * + * 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 "Zigbee.h" + +/* Zigbee carbon dioxide sensor configuration */ +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; + +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Optional: set Zigbee device name and model + zbCarbonDioxideSensor.setManufacturerAndModel("Espressif", "ZigbeeCarbonDioxideSensor"); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 1500); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // Set reporting interval for carbon dioxide measurement to be done every 30 seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (carbon dioxide change in ppm) + // if min = 1 and max = 0, reporting is sent only when carbon dioxide changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or when carbon dioxide changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change + zbCarbonDioxideSensor.setReporting(0, 30, 0); +} + +void loop() { + static uint32_t timeCounter = 0; + // Read carbon dioxide sensor every 2s + if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s + // Read sensor value - here is chip temperature used + 300 as a dummy value for demonstration + uint16_t carbon_dioxide_value = 300 + (uint16_t)temperatureRead(); + Serial.printf("Updating carbon dioxide sensor value to %d ppm\r\n", carbon_dioxide_value); + zbCarbonDioxideSensor.setCarbonDioxide(carbon_dioxide_value); + } + + // Checking button for factory reset and reporting + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + zbCarbonDioxideSensor.report(); + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/ci.json new file mode 100644 index 00000000000..7b7ccef8ed7 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_CarbonDioxide_Sensor/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} 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 c03d26d3aba..e84720d4863 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 @@ -33,16 +33,21 @@ #include "Zigbee.h" -#define LED_PIN RGB_BUILTIN -#define BUTTON_PIN 9 // C6/H2 Boot button -#define ZIGBEE_LIGHT_ENDPOINT 10 +/* Zigbee color dimmable light configuration */ +#define ZIGBEE_RGB_LIGHT_ENDPOINT 10 +uint8_t led = RGB_BUILTIN; +uint8_t button = BOOT_PIN; -ZigbeeColorDimmableLight zbColorLight = ZigbeeColorDimmableLight(ZIGBEE_LIGHT_ENDPOINT); +ZigbeeColorDimmableLight zbColorLight = ZigbeeColorDimmableLight(ZIGBEE_RGB_LIGHT_ENDPOINT); /********************* RGB LED functions **************************/ void setRGBLight(bool state, uint8_t red, uint8_t green, uint8_t blue, uint8_t level) { + if (!state) { + rgbLedWrite(led, 0, 0, 0); + return; + } float brightness = (float)level / 255; - rgbLedWrite(LED_PIN, red * brightness, green * brightness, blue * brightness); + rgbLedWrite(led, red * brightness, green * brightness, blue * brightness); } // Create a task on identify call to handle the identify function @@ -54,17 +59,19 @@ void identify(uint16_t time) { zbColorLight.restoreLight(); return; } - rgbLedWrite(LED_PIN, 255 * blink, 255 * blink, 255 * blink); + rgbLedWrite(led, 255 * blink, 255 * blink, 255 * blink); blink = !blink; } /********************* Arduino functions **************************/ void setup() { + Serial.begin(115200); + // Init RMT and leave light OFF - rgbLedWrite(LED_PIN, 0, 0, 0); + rgbLedWrite(led, 0, 0, 0); // Init button for factory reset - pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(button, INPUT_PULLUP); // Set callback function for light change zbColorLight.onLightChange(setRGBLight); @@ -76,28 +83,40 @@ void setup() { zbColorLight.setManufacturerAndModel("Espressif", "ZBColorLightBulb"); // Add endpoint to Zigbee Core - log_d("Adding ZigbeeLight endpoint to Zigbee Core"); + Serial.println("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(); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); } void loop() { // Checking button for factory reset - if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + if (digitalRead(button) == LOW) { // Push button pressed // Key debounce handling delay(100); int startTime = millis(); - while (digitalRead(BUTTON_PIN) == LOW) { + while (digitalRead(button) == 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"); + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); Zigbee.factoryReset(); } } + // Increase blightness by 50 every time the button is pressed + zbColorLight.setLightLevel(zbColorLight.getLightLevel() + 50); } delay(100); } 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 6d6c7b163dd..a313f3c0594 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 @@ -37,23 +37,19 @@ #include "Zigbee.h" -/* Switch configuration */ -#define SWITCH_PIN 9 // ESP32-C6/H2 Boot button +/* Zigbee color dimmer switch configuration */ #define SWITCH_ENDPOINT_NUMBER 5 +uint8_t button = BOOT_PIN; /* 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_PULLUP); + pinMode(button, INPUT_PULLUP); //Optional: set Zigbee device name and model zbSwitch.setManufacturerAndModel("Espressif", "ZigbeeSwitch"); @@ -68,11 +64,15 @@ void setup() { Zigbee.setRebootOpenNetwork(180); //When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode - Zigbee.begin(ZIGBEE_COORDINATOR); + if (!Zigbee.begin(ZIGBEE_COORDINATOR)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } Serial.println("Waiting for Light to bound to the switch"); //Wait for switch to bound to a light: - while (!zbSwitch.isBound()) { + while (!zbSwitch.bound()) { Serial.printf("."); delay(500); } @@ -81,9 +81,9 @@ void setup() { void loop() { // Handle button switch in loop() - if (digitalRead(SWITCH_PIN) == LOW) { // Push button pressed + if (digitalRead(button) == LOW) { // Push button pressed // Key debounce handling - while (digitalRead(SWITCH_PIN) == LOW) { + while (digitalRead(button) == LOW) { delay(50); } // Toggle light @@ -142,6 +142,6 @@ void loop() { static uint32_t last_print = 0; if (millis() - last_print > 30000) { last_print = millis(); - zbSwitch.printBoundDevices(); + zbSwitch.printBoundDevices(Serial); } } diff --git a/libraries/Zigbee/examples/Zigbee_Dimmable_Light/README.md b/libraries/Zigbee/examples/Zigbee_Dimmable_Light/README.md new file mode 100644 index 00000000000..e5bf51b660c --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Dimmable_Light/README.md @@ -0,0 +1,68 @@ +# Arduino-ESP32 Zigbee Dimmable Light Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) dimmable light. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming +* Board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the Zigbee_Dimmable_Light example +* Zigbee network / coordinator (Other board with switch examples or Zigbee2mqtt or ZigbeeHomeAssistant like application) + +### 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_Dimmable_Light/Zigbee_Dimmable_Light.ino b/libraries/Zigbee/examples/Zigbee_Dimmable_Light/Zigbee_Dimmable_Light.ino new file mode 100644 index 00000000000..c77a7e742d1 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Dimmable_Light/Zigbee_Dimmable_Light.ino @@ -0,0 +1,121 @@ +// 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 Dimmable light bulb. + * + * The example demonstrates how to use Zigbee library to create an end device with + * 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 [FaBjE](https://github.com/FaBjE) based on examples 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 "Zigbee.h" + +/* Zigbee dimmable light configuration */ +#define ZIGBEE_LIGHT_ENDPOINT 10 +uint8_t led = RGB_BUILTIN; +uint8_t button = BOOT_PIN; + +ZigbeeDimmableLight zbDimmableLight = ZigbeeDimmableLight(ZIGBEE_LIGHT_ENDPOINT); + +/********************* RGB LED functions **************************/ +void setLight(bool state, uint8_t level) { + if (!state) { + rgbLedWrite(led, 0, 0, 0); + return; + } + rgbLedWrite(led, level, level, level); +} + +// 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 + zbDimmableLight.restoreLight(); + return; + } + rgbLedWrite(led, 255 * blink, 255 * blink, 255 * blink); + blink = !blink; +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init RMT and leave light OFF + rgbLedWrite(led, 0, 0, 0); + + // Init button for factory reset + pinMode(button, INPUT_PULLUP); + + // Set callback function for light change + zbDimmableLight.onLightChange(setLight); + + // Optional: Set callback function for device identify + zbDimmableLight.onIdentify(identify); + + // Optional: Set Zigbee device name and model + zbDimmableLight.setManufacturerAndModel("Espressif", "ZBLightBulb"); + + // Add endpoint to Zigbee Core + Serial.println("Adding ZigbeeLight endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbDimmableLight); + + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); +} + +void loop() { + // Checking button for factory reset + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + // Increase blightness by 50 every time the button is pressed + zbDimmableLight.setLightLevel(zbDimmableLight.getLightLevel() + 50); + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Dimmable_Light/ci.json b/libraries/Zigbee/examples/Zigbee_Dimmable_Light/ci.json new file mode 100644 index 00000000000..7b7ccef8ed7 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Dimmable_Light/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/README.md new file mode 100644 index 00000000000..0c5dcd013f2 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/README.md @@ -0,0 +1,57 @@ +# Arduino-ESP32 Zigbee Occupancy Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) occupancy sensor (PIR). + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Sensor GPIO by changing the `sensor_pin` variable. + +#### 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. + +***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_Occupancy_Sensor/Zigbee_Occupancy_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/Zigbee_Occupancy_Sensor.ino new file mode 100644 index 00000000000..46afdf3d273 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/Zigbee_Occupancy_Sensor.ino @@ -0,0 +1,103 @@ +// 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 occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * 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 "Zigbee.h" + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 4; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + +void setup() { + Serial.begin(115200); + + // Init button + PIR sensor + pinMode(button, INPUT_PULLUP); + pinMode(sensor_pin, INPUT); + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor"); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); +} + +void loop() { + // Checking PIR sensor for occupancy change + static bool occupancy = false; + if (digitalRead(sensor_pin) == HIGH && !occupancy) { + // Update occupancy sensor value + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + occupancy = true; + } else if (digitalRead(sensor_pin) == LOW && occupancy) { + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + occupancy = false; + } + + // Checking button for factory reset + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/ci.json new file mode 100644 index 00000000000..7b7ccef8ed7 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} 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 30e3cd2d109..6db8bd7b022 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 @@ -32,25 +32,28 @@ #include "Zigbee.h" -#define LED_PIN RGB_BUILTIN -#define BUTTON_PIN 9 // ESP32-C6/H2 Boot button +/* Zigbee light bulb configuration */ #define ZIGBEE_LIGHT_ENDPOINT 10 +uint8_t led = RGB_BUILTIN; +uint8_t button = BOOT_PIN; ZigbeeLight zbLight = ZigbeeLight(ZIGBEE_LIGHT_ENDPOINT); /********************* RGB LED functions **************************/ void setLED(bool value) { - digitalWrite(LED_PIN, value); + digitalWrite(led, value); } /********************* Arduino functions **************************/ void setup() { + Serial.begin(115200); + // 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); + pinMode(led, OUTPUT); + digitalWrite(led, LOW); // Init button for factory reset - pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(button, INPUT_PULLUP); //Optional: set Zigbee device name and model zbLight.setManufacturerAndModel("Espressif", "ZBLightBulb"); @@ -59,28 +62,40 @@ void setup() { zbLight.onLightChange(setLED); //Add endpoint to Zigbee Core - log_d("Adding ZigbeeLight endpoint to Zigbee Core"); + Serial.println("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(); + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); } void loop() { // Checking button for factory reset - if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + if (digitalRead(button) == LOW) { // Push button pressed // Key debounce handling delay(100); int startTime = millis(); - while (digitalRead(BUTTON_PIN) == LOW) { + while (digitalRead(button) == 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"); + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); Zigbee.factoryReset(); } } + // Toggle light by pressing the button + zbLight.setLight(!zbLight.getLightState()); } delay(100); } 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 index 69cf6654a41..56d23cdc95f 100644 --- 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 @@ -33,10 +33,10 @@ #include "Zigbee.h" +/* Zigbee switch configuration */ #define SWITCH_ENDPOINT_NUMBER 5 -/* Switch configuration */ -#define GPIO_INPUT_IO_TOGGLE_SWITCH 9 +#define GPIO_INPUT_IO_TOGGLE_SWITCH BOOT_PIN #define PAIR_SIZE(TYPE_STR_PAIR) (sizeof(TYPE_STR_PAIR) / sizeof(TYPE_STR_PAIR[0])) typedef enum { @@ -70,6 +70,7 @@ ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER); static void onZbButton(SwitchData *button_func_pair) { if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) { // Send toggle command to the light + Serial.println("Toggling light"); zbSwitch.lightToggle(); } } @@ -93,11 +94,7 @@ static void enableGpioInterrupt(bool enabled) { /********************* Arduino functions **************************/ void setup() { - Serial.begin(115200); - while (!Serial) { - delay(10); - } //Optional: set Zigbee device name and model zbSwitch.setManufacturerAndModel("Espressif", "ZigbeeSwitch"); @@ -106,7 +103,7 @@ void setup() { zbSwitch.allowMultipleBinding(true); //Add endpoint to Zigbee Core - log_d("Adding ZigbeeSwitch endpoint to Zigbee Core"); + Serial.println("Adding ZigbeeSwitch endpoint to Zigbee Core"); Zigbee.addEndpoint(&zbSwitch); //Open network for 180 seconds after boot @@ -118,34 +115,36 @@ void setup() { /* 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); + Serial.println("Queue creating failed, rebooting..."); + ESP.restart(); } 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); + if (!Zigbee.begin(ZIGBEE_COORDINATOR)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } Serial.println("Waiting for Light to bound to the switch"); //Wait for switch to bound to a light: - while (!zbSwitch.isBound()) { + while (!zbSwitch.bound()) { Serial.printf("."); delay(500); } - // Optional: read manufacturer and model name from the bound light + // Optional: List all bound devices and read manufacturer and model name 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("Device on endpoint %d, short address: 0x%x\r\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] + "IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n", device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], + device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0] ); - 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.printf("Light manufacturer: %s\r\n", zbSwitch.readManufacturer(device->endpoint, device->short_addr, device->ieee_addr)); + Serial.printf("Light model: %s\r\n", zbSwitch.readModel(device->endpoint, device->short_addr, device->ieee_addr)); } Serial.println(); @@ -188,6 +187,6 @@ void loop() { static uint32_t lastPrint = 0; if (millis() - lastPrint > 10000) { lastPrint = millis(); - zbSwitch.printBoundDevices(); + zbSwitch.printBoundDevices(Serial); } } diff --git a/libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/README.md new file mode 100644 index 00000000000..964c7503027 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/README.md @@ -0,0 +1,72 @@ +# Arduino-ESP32 Zigbee Pressure + Flow Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) simple sensor device type with pressure and flow measuring. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Pressure + Flow Sensor Functions + + * After this board first starts up, it would be configured locally to report the pressure and flow on change or every 30 seconds. + * By clicking the button (BOOT) on this board, this board will immediately send a report of the current measured flow and pressure to the network. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +In this example, the internal temperature sensor is used to demonstrate reading of the flow and pressure sensors. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (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 + +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_Pressure_Flow_Sensor/Zigbee_Pressure_Flow_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/Zigbee_Pressure_Flow_Sensor.ino new file mode 100644 index 00000000000..a652a22c493 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/Zigbee_Pressure_Flow_Sensor.ino @@ -0,0 +1,128 @@ +// 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 end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee flow + pressure sensor configuration */ +#define FLOW_SENSOR_ENDPOINT_NUMBER 10 +#define PRESSURE_SENSOR_ENDPOINT_NUMBER 11 + +uint8_t button = BOOT_PIN; + +ZigbeeFlowSensor zbFlowSensor = ZigbeeFlowSensor(FLOW_SENSOR_ENDPOINT_NUMBER); +ZigbeePressureSensor zbPressureSensor = ZigbeePressureSensor(PRESSURE_SENSOR_ENDPOINT_NUMBER); + +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Optional: set Zigbee device name and model + zbFlowSensor.setManufacturerAndModel("Espressif", "ZigbeeFlowSensor"); + + // Set minimum and maximum flow measurement value in 0,1 m3/h + zbFlowSensor.setMinMaxValue(0.0, 100.0); + + // Optional: Set tolerance for flow measurement in 0,1 m3/h + zbFlowSensor.setTolerance(1.0); + + // Optional: set Zigbee device name and model + zbPressureSensor.setManufacturerAndModel("Espressif", "ZigbeePressureSensor"); + + // Set minimum and maximum pressure measurement value in hPa + zbPressureSensor.setMinMaxValue(0, 10000); + + // Optional: Set tolerance for pressure measurement in hPa + zbPressureSensor.setTolerance(1); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbFlowSensor); + Zigbee.addEndpoint(&zbPressureSensor); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // Set reporting interval for flow and pressure measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (pressure change in hPa, flow change in 0,1 m3/h) + // 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 delta change + zbFlowSensor.setReporting(0, 30, 1.0); + zbPressureSensor.setReporting(0, 30, 1); +} + +void loop() { + static uint32_t timeCounter = 0; + + // Read flow and pressure sensors every 2s + if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s + float flow_value = temperatureRead(); + uint16_t pressure_value = (uint16_t)temperatureRead() * 100; //*100 for demonstration so the value is in 1000-3000hPa + Serial.printf("Updating flow sensor value to %.2f m3/h\r\n", flow_value); + zbFlowSensor.setFlow(flow_value); + Serial.printf("Updating pressure sensor value to %d hPa\r\n", pressure_value); + zbPressureSensor.setPressure(pressure_value); + } + + // Checking button for factory reset and reporting + if (digitalRead(button) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + } + } + zbFlowSensor.report(); + zbPressureSensor.report(); + } + delay(100); +} diff --git a/libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/ci.json b/libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/ci.json new file mode 100644 index 00000000000..7b7ccef8ed7 --- /dev/null +++ b/libraries/Zigbee/examples/Zigbee_Pressure_Flow_Sensor/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} diff --git a/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino b/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino index 7d59fb2907d..eab6ecfd76e 100644 --- a/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino +++ b/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino @@ -32,7 +32,7 @@ #include "Zigbee.h" #ifdef ZIGBEE_MODE_ZCZR -zigbee_role_t role = ZIGBEE_ROUTER; // or can be ZIGBEE_COORDINATOR, but it wont scan itself +zigbee_role_t role = ZIGBEE_ROUTER; // or can be ZIGBEE_COORDINATOR, but it won't scan itself #else zigbee_role_t role = ZIGBEE_END_DEVICE; #endif @@ -76,19 +76,15 @@ void printScannedNetworks(uint16_t networksFound) { 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); + if (!Zigbee.begin(role)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); } - Serial.println("Setup done"); + Serial.println("Setup done, starting Zigbee network scan..."); // Start Zigbee Network Scan with default parameters (all channels, scan time 5) Zigbee.scanNetworks(); } @@ -98,7 +94,7 @@ void loop() { 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."); + Serial.println("Zigbee scan has failed. Starting again."); Zigbee.scanNetworks(); } // other option is status ZB_SCAN_RUNNING - just wait. diff --git a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/README.md b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/README.md index d88b01cda3a..afaa12c0bfa 100644 --- a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/README.md +++ b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/README.md @@ -24,7 +24,7 @@ Currently, this example supports the following targets. ### Configure the Project In this example, to demonstrate the functionality the chip temperature is used and reported as temperature and humidity. -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). +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). #### Using Arduino IDE diff --git a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino index 530995a8427..60bd784cca9 100644 --- a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino +++ b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino @@ -27,17 +27,19 @@ */ #ifndef ZIGBEE_MODE_ED -#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" #endif #include "Zigbee.h" -#define BUTTON_PIN 9 //Boot button for C6/H2 +/* Zigbee temperature + humidity sensor configuration */ #define TEMP_SENSOR_ENDPOINT_NUMBER 10 #define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ #define TIME_TO_SLEEP 55 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ +uint8_t button = BOOT_PIN; + ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); /************************ Temp sensor *****************************/ @@ -53,19 +55,23 @@ void meausureAndSleep() { zbTempSensor.setHumidity(humidity); // Report temperature and humidity values - zbTempSensor.reportTemperature(); - zbTempSensor.reportHumidity(); + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); - log_d("Temperature: %.2f°C, Humidity: %.2f%", temperature, humidity); + // Add small delay to allow the data to be sent before going to sleep + delay(100); // Put device to deep sleep + Serial.println("Going to sleep now"); esp_deep_sleep_start(); } /********************* Arduino functions **************************/ void setup() { + Serial.begin(115200); + // Init button switch - pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(button, INPUT_PULLUP); // Configure the wake up source and set to wake up every 5 seconds esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); @@ -94,27 +100,35 @@ void setup() { zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; // When all EPs are registered, start Zigbee in End Device mode - Zigbee.begin(&zigbeeConfig, false); - - // Wait for Zigbee to start - while (!Zigbee.isStarted()) { + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); delay(100); } + Serial.println(); + Serial.println("Successfully connected to Zigbee network"); - // Delay 5s to allow establishing connection with coordinator, needed for sleepy devices - delay(5000); + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); } void loop() { // Checking button for factory reset - if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + if (digitalRead(button) == LOW) { // Push button pressed // Key debounce handling delay(100); int startTime = millis(); - while (digitalRead(BUTTON_PIN) == LOW) { + while (digitalRead(button) == LOW) { delay(50); if ((millis() - startTime) > 3000) { // If key pressed for more than 3secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); Zigbee.factoryReset(); } } diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/README.md b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/README.md index f3dd9248f87..577bd7c8058 100644 --- a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/README.md +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/README.md @@ -28,7 +28,7 @@ Functions: ### Configure the Project In this example, the internal temperature sensor task is reading the chip temperature. -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). +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). #### Using Arduino IDE 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 c5ca00decd6..27aa2db97bd 100644 --- a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino @@ -27,13 +27,14 @@ */ #ifndef ZIGBEE_MODE_ED -#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" #endif #include "Zigbee.h" -#define BUTTON_PIN 9 //Boot button for C6/H2 +/* Zigbee temperature sensor configuration */ #define TEMP_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); @@ -42,7 +43,7 @@ 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); + Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); // Update temperature value in Temperature sensor EP zbTempSensor.setTemperature(tsens_value); delay(1000); @@ -51,14 +52,10 @@ static void temp_sensor_value_update(void *arg) { /********************* Arduino functions **************************/ void setup() { - Serial.begin(115200); - while (!Serial) { - delay(10); - } // Init button switch - pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(button, INPUT_PULLUP); // Optional: set Zigbee device name and model zbTempSensor.setManufacturerAndModel("Espressif", "ZigbeeTempSensor"); @@ -66,20 +63,33 @@ void setup() { // 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) + // Optional: 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); + Serial.println("Starting Zigbee..."); // When all EPs are registered, start Zigbee in End Device mode - Zigbee.begin(); + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); // 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) + // min_interval and max_interval in seconds, delta (temp change in 0,1 °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 @@ -88,15 +98,16 @@ void setup() { void loop() { // Checking button for factory reset - if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + if (digitalRead(button) == LOW) { // Push button pressed // Key debounce handling delay(100); int startTime = millis(); - while (digitalRead(BUTTON_PIN) == LOW) { + while (digitalRead(button) == 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"); + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); Zigbee.factoryReset(); } } diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino index 565d9e64919..a4720feeba4 100644 --- a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino +++ b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino @@ -33,8 +33,9 @@ #include "Zigbee.h" -#define BUTTON_PIN 9 // Boot button for C6/H2 +/* Zigbee thermostat configuration */ #define THERMOSTAT_ENDPOINT_NUMBER 5 +uint8_t button = BOOT_PIN; ZigbeeThermostat zbThermostat = ZigbeeThermostat(THERMOSTAT_ENDPOINT_NUMBER); @@ -59,12 +60,9 @@ void recieveSensorConfig(float min_temp, float max_temp, float tolerance) { /********************* Arduino functions **************************/ void setup() { Serial.begin(115200); - while (!Serial) { - delay(10); - } // Init button switch - pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(button, INPUT_PULLUP); // Set callback functions for temperature and configuration receive zbThermostat.onTempRecieve(recieveSensorTemp); @@ -80,27 +78,30 @@ void setup() { 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"); + if (!Zigbee.begin(ZIGBEE_COORDINATOR)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } - //Wait for switch to bound to a light: - while (!zbThermostat.isBound()) { + Serial.println("Waiting for Temperature sensor to bound to the thermostat"); + while (!zbThermostat.bound()) { Serial.printf("."); delay(500); } + Serial.println(); + // Get temperature sensor configuration zbThermostat.getSensorSettings(); - Serial.println(); } void loop() { // Handle button switch in loop() - if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + if (digitalRead(button) == LOW) { // Push button pressed // Key debounce handling - while (digitalRead(BUTTON_PIN) == LOW) { + while (digitalRead(button) == LOW) { delay(50); } diff --git a/libraries/Zigbee/keywords.txt b/libraries/Zigbee/keywords.txt index 53ce5fffe2a..483d54eb712 100644 --- a/libraries/Zigbee/keywords.txt +++ b/libraries/Zigbee/keywords.txt @@ -18,6 +18,9 @@ ZigbeeColorDimmableLight KEYWORD1 ZigbeeColorDimmerSwitch KEYWORD1 ZigbeeTempSensor KEYWORD1 ZigbeeThermostat KEYWORD1 +ZigbeeFlowSensor KEYWORD1 +ZigbeePressureSensor KEYWORD1 +ZigbeeOccupancySensor KEYWORD1 # Other zigbee_role_t KEYWORD1 @@ -30,14 +33,20 @@ zigbee_scan_result_t KEYWORD1 ####################################### # ZigbeeCore -isStarted KEYWORD2 +begin KEYWORD2 +started KEYWORD2 +connected KEYWORD2 +getRole KEYWORD2 addEndpoint KEYWORD2 setRadioConfig KEYWORD2 -setHostConfig KEYWORD2 getRadioConfig KEYWORD2 +setHostConfig KEYWORD2 getHostConfig KEYWORD2 setPrimaryChannelMask KEYWORD2 +setScanDuration KEYWORD2 +getScanDuration KEYWORD2 setRebootOpenNetwork KEYWORD2 +openNetwork KEYWORD2 scanNetworks KEYWORD2 scanComplete KEYWORD2 getScanResult KEYWORD2 @@ -45,21 +54,33 @@ scanDelete KEYWORD2 factoryReset KEYWORD2 # Common ZigbeeEP +setEpConfig KEYWORD2 setVersion KEYWORD2 -setManufacturerAndModel KEYWORD2 -is_bound KEYWORD2 +getEndpoint KEYWORD2 printBoundDevices KEYWORD2 +getBoundDevices KEYWORD2 +bound KEYWORD2 allowMultipleBinding KEYWORD2 +setManufacturerAndModel KEYWORD2 +setPowerSource KEYWORD2 +setBatteryPercentage KEYWORD2 +reportBatteryPercentage KEYWORD2 +readManufacturer KEYWORD2 +readModel KEYWORD2 +onIdentify KEYWORD2 # ZigbeeLight + ZigbeeColorDimmableLight -setOnOff KEYWORD2 -sceneControl KEYWORD2 -setOnOffTime KEYWORD2 -setOffWaitTime KEYWORD2 -setLevel KEYWORD2 -setColor KEYWORD2 -setColorSaturation KEYWORD2 -setColorHue KEYWORD2 +onLightChange KEYWORD2 +restoreLight KEYWORD2 +setLight KEYWORD2 +setLightState KEYWORD2 +setLightLevel KEYWORD2 +setLightColor KEYWORD2 +getLightState KEYWORD2 +getLightLevel KEYWORD2 +getLightRed KEYWORD2 +getLightGreen KEYWORD2 +getLightBlue KEYWORD2 # ZigbeeSwitch + ZigbeeColorDimmerSwitch lightToggle KEYWORD2 @@ -70,23 +91,40 @@ lightOnWithTimedOff KEYWORD2 lightOnWithSceneRecall KEYWORD2 setLightLevel KEYWORD2 setLightColor KEYWORD2 -setLightColorSaturation KEYWORD2 -setLightColorHue KEYWORD2 -# ZigbeeTempSensor -setTemperature KEYWORD2 +# ZigbeeThermostat +onTempRecieve KEYWORD2 +onConfigRecieve KEYWORD2 +getTemperature KEYWORD2 +getSensorSettings KEYWORD2 +setTemperatureReporting KEYWORD2 + +# Common Zigbee Sensor setMinMaxValue KEYWORD2 setTolerance KEYWORD2 setReporting KEYWORD2 +report KEYWORD2 + +# ZigbeeTempSensor + humidity +setTemperature KEYWORD2 reportTemperature KEYWORD2 +addHumiditySensor KEYWORD2 +setHumidity KEYWORD2 +setHumidityReporting KEYWORD2 +reportHumidity KEYWORD2 -# ZigbeeThermostat -temperatureRead KEYWORD2 -temperatureMin KEYWORD2 -temperatureMax KEYWORD2 -temperatureTolerance KEYWORD2 -getTemperature KEYWORD2 -setTemperatureReporting KEYWORD2 +# ZigbeeFlowSensor +setFlow KEYWORD2 + +# ZigbeePressureSensor +setPressure KEYWORD2 + +# ZigbeeOccupancySensor +setOccupancy KEYWORD2 +setSensorType KEYWORD2 + +# ZigbeeCarbonDioxideSensor +setCarbonDioxide KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/libraries/Zigbee/library.properties b/libraries/Zigbee/library.properties index 4d66f470378..2b1f041fc94 100644 --- a/libraries/Zigbee/library.properties +++ b/libraries/Zigbee/library.properties @@ -1,5 +1,5 @@ name=Zigbee -version=3.0.5 +version=3.1.0 author=P-R-O-C-H-Y maintainer=Jan Procházka sentence=Enables zigbee connection with the ESP32 diff --git a/libraries/Zigbee/src/Zigbee.h b/libraries/Zigbee/src/Zigbee.h index 98674a9d115..cf58dc8d5d8 100644 --- a/libraries/Zigbee/src/Zigbee.h +++ b/libraries/Zigbee/src/Zigbee.h @@ -9,7 +9,12 @@ // Endpoints #include "ep/ZigbeeLight.h" #include "ep/ZigbeeSwitch.h" +#include "ep/ZigbeeDimmableLight.h" #include "ep/ZigbeeColorDimmableLight.h" #include "ep/ZigbeeColorDimmerSwitch.h" #include "ep/ZigbeeTempSensor.h" #include "ep/ZigbeeThermostat.h" +#include "ep/ZigbeePressureSensor.h" +#include "ep/ZigbeeFlowSensor.h" +#include "ep/ZigbeeOccupancySensor.h" +#include "ep/ZigbeeCarbonDioxideSensor.h" diff --git a/libraries/Zigbee/src/ZigbeeCore.cpp b/libraries/Zigbee/src/ZigbeeCore.cpp index 31f9ab1910f..cc0111f2644 100644 --- a/libraries/Zigbee/src/ZigbeeCore.cpp +++ b/libraries/Zigbee/src/ZigbeeCore.cpp @@ -1,11 +1,13 @@ /* Zigbee Core Functions */ #include "ZigbeeCore.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "ZigbeeHandlers.cpp" #include "Arduino.h" +#define ZB_INIT_TIMEOUT 30000 // 30 seconds + extern "C" void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr); static bool edBatteryPowered = false; @@ -17,6 +19,15 @@ ZigbeeCore::ZigbeeCore() { _open_network = 0; _scan_status = ZB_SCAN_FAILED; _started = false; + _connected = false; + _scan_duration = 3; // default scan duration + _rx_on_when_idle = true; + if (!lock) { + lock = xSemaphoreCreateBinary(); + if (lock == NULL) { + log_e("Semaphore creation failed"); + } + } } ZigbeeCore::~ZigbeeCore() {} @@ -25,10 +36,14 @@ static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, bool ZigbeeCore::begin(esp_zb_cfg_t *role_cfg, bool erase_nvs) { if (!zigbeeInit(role_cfg, erase_nvs)) { + log_e("ZigbeeCore begin failed"); return false; } _role = (zigbee_role_t)role_cfg->esp_zb_role; - return true; + if (xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) { + log_e("ZigbeeCore begin timeout"); + } + return started(); } bool ZigbeeCore::begin(zigbee_role_t role, bool erase_nvs) { @@ -57,7 +72,10 @@ bool ZigbeeCore::begin(zigbee_role_t role, bool erase_nvs) { } default: log_e("Invalid Zigbee Role"); return false; } - return status; + if (!status || xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) { + log_e("ZigbeeCore begin failed or timeout"); + } + return started(); } void ZigbeeCore::addEndpoint(ZigbeeEP *ep) { @@ -74,12 +92,14 @@ void ZigbeeCore::addEndpoint(ZigbeeEP *ep) { } static void esp_zb_task(void *pvParameters) { + esp_zb_bdb_set_scan_duration(Zigbee.getScanDuration()); + /* initialize Zigbee stack */ ESP_ERROR_CHECK(esp_zb_start(false)); //NOTE: This is a workaround to make battery powered devices to be discovered as battery powered if (((zigbee_role_t)Zigbee.getRole() == ZIGBEE_END_DEVICE) && edBatteryPowered) { - zb_set_ed_node_descriptor(0, 0, 0); + zb_set_ed_node_descriptor(0, Zigbee.getRxOnWhenIdle(), 1); } esp_zb_stack_main_loop(); @@ -162,12 +182,20 @@ void ZigbeeCore::setPrimaryChannelMask(uint32_t mask) { _primary_channel_mask = mask; } +void ZigbeeCore::setScanDuration(uint8_t duration) { + if (duration < 1 || duration > 4) { + log_e("Invalid scan duration, must be between 1 and 4"); + return; + } + _scan_duration = duration; +} + void ZigbeeCore::setRebootOpenNetwork(uint8_t time) { _open_network = time; } void ZigbeeCore::openNetwork(uint8_t time) { - if (isStarted()) { + if (started()) { log_v("Opening network for joining for %d seconds", time); esp_zb_bdb_open_network(time); } @@ -203,21 +231,25 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { } else { log_i("Start network steering"); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); + Zigbee._started = true; + xSemaphoreGive(Zigbee.lock); } - //----------------- - } else { log_i("Device rebooted"); Zigbee._started = true; + xSemaphoreGive(Zigbee.lock); 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 { + Zigbee._connected = true; } + Zigbee.searchBindings(); } } else { /* commissioning failed */ - log_e("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); - esp_restart(); + log_w("Commissioning failed, trying again...", esp_err_to_name(err_status)); + esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_INITIALIZATION, 500); } break; case ESP_ZB_BDB_SIGNAL_FORMATION: // Coordinator @@ -243,6 +275,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { log_i("Network steering started"); } Zigbee._started = true; + xSemaphoreGive(Zigbee.lock); } else { if (err_status == ESP_OK) { esp_zb_ieee_addr_t extended_pan_id; @@ -252,7 +285,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { 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() ); - Zigbee._started = true; + Zigbee._connected = true; } 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); @@ -278,10 +311,9 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { 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()) { + if (!(*it)->bound() || (*it)->epAllowMultipleBinding()) { (*it)->findEndpoint(&cmd_req); } } @@ -298,6 +330,12 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { } } break; + case ESP_ZB_ZDO_SIGNAL_LEAVE: // End Device + Router + // Device was removed from the network, factory reset the device + if ((zigbee_role_t)Zigbee.getRole() != ZIGBEE_COORDINATOR) { + Zigbee.factoryReset(); + } + 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; } } @@ -335,7 +373,7 @@ void ZigbeeCore::scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t co } void ZigbeeCore::scanNetworks(u_int32_t channel_mask, u_int8_t scan_duration) { - if (!isStarted()) { + if (!started()) { log_e("Zigbee stack is not started, cannot scan networks"); return; } @@ -360,6 +398,75 @@ void ZigbeeCore::scanDelete() { _scan_status = ZB_SCAN_FAILED; } +// Recall bounded devices from the binding table after reboot +void ZigbeeCore::bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx) { + bool done = true; + esp_zb_zdo_mgmt_bind_param_t *req = (esp_zb_zdo_mgmt_bind_param_t *)user_ctx; + esp_zb_zdp_status_t zdo_status = (esp_zb_zdp_status_t)table_info->status; + log_d("Binding table callback for address 0x%04x with status %d", req->dst_addr, zdo_status); + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + // Print binding table log simple + log_d("Binding table info: total %d, index %d, count %d", table_info->total, table_info->index, table_info->count); + + if (table_info->total == 0) { + log_d("No binding table entries found"); + free(req); + return; + } + + esp_zb_zdo_binding_table_record_t *record = table_info->record; + for (int i = 0; i < table_info->count; i++) { + log_d( + "Binding table record: src_endp %d, dst_endp %d, cluster_id 0x%04x, dst_addr_mode %d", record->src_endp, record->dst_endp, record->cluster_id, + record->dst_addr_mode + ); + + zb_device_params_t *device = (zb_device_params_t *)calloc(1, sizeof(zb_device_params_t)); + device->endpoint = record->dst_endp; + if (record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT || record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT) { + device->short_addr = record->dst_address.addr_short; + } else { //ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT + memcpy(device->ieee_addr, record->dst_address.addr_long, sizeof(esp_zb_ieee_addr_t)); + } + + // Add to list of bound devices of proper endpoint + for (std::list::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { + if ((*it)->getEndpoint() == record->src_endp) { + (*it)->addBoundDevice(device); + log_d( + "Device bound to EP %d -> device endpoint: %d, short addr: 0x%04x, ieee addr: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", record->src_endp, + device->endpoint, device->short_addr, device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], + device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0] + ); + } + } + record = record->next; + } + + // Continue reading the binding table + if (table_info->index + table_info->count < table_info->total) { + /* There are unreported binding table entries, request for them. */ + req->start_index = table_info->index + table_info->count; + esp_zb_zdo_binding_table_req(req, bindingTableCb, req); + done = false; + } + } + + if (done) { + // Print bound devices + log_d("Filling bounded devices finished"); + free(req); + } +} + +void ZigbeeCore::searchBindings() { + esp_zb_zdo_mgmt_bind_param_t *mb_req = (esp_zb_zdo_mgmt_bind_param_t *)malloc(sizeof(esp_zb_zdo_mgmt_bind_param_t)); + mb_req->dst_addr = esp_zb_get_short_address(); + mb_req->start_index = 0; + log_d("Requesting binding table for address 0x%04x", mb_req->dst_addr); + esp_zb_zdo_binding_table_req(mb_req, bindingTableCb, (void *)mb_req); +} + // Function to convert enum value to string const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId) { switch (deviceId) { @@ -407,4 +514,4 @@ const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceI ZigbeeCore Zigbee = ZigbeeCore(); -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ZigbeeCore.h b/libraries/Zigbee/src/ZigbeeCore.h index 1044a9c737c..c72a60d81c4 100644 --- a/libraries/Zigbee/src/ZigbeeCore.h +++ b/libraries/Zigbee/src/ZigbeeCore.h @@ -3,7 +3,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_IEEE802154_SUPPORTED +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "esp_zigbee_core.h" #include "zdo/esp_zigbee_zdo_common.h" @@ -65,17 +66,23 @@ class ZigbeeCore { esp_zb_host_config_t _host_config; uint32_t _primary_channel_mask; int16_t _scan_status; + uint8_t _scan_duration; + bool _rx_on_when_idle; esp_zb_ep_list_t *_zb_ep_list; zigbee_role_t _role; bool _started; + bool _connected; uint8_t _open_network; zigbee_scan_result_t *_scan_result; + SemaphoreHandle_t lock; 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); + void searchBindings(); + static void bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx); public: ZigbeeCore(); @@ -87,9 +94,12 @@ class ZigbeeCore { bool begin(esp_zb_cfg_t *role_cfg, bool erase_nvs = false); // bool end(); - bool isStarted() { + bool started() { return _started; } + bool connected() { + return _connected; + } zigbee_role_t getRole() { return _role; } @@ -103,7 +113,19 @@ class ZigbeeCore { void setHostConfig(esp_zb_host_config_t config); esp_zb_host_config_t getHostConfig(); - void setPrimaryChannelMask(uint32_t mask); + void setPrimaryChannelMask(uint32_t mask); // By default all channels are scanned (11-26) -> mask 0x07FFF800 + void setScanDuration(uint8_t duration); // Can be set from 1 - 4. 1 is fastest, 4 is slowest + uint8_t getScanDuration() { + return _scan_duration; + } + + void setRxOnWhenIdle(bool rx_on_when_idle) { + _rx_on_when_idle = rx_on_when_idle; + } + bool getRxOnWhenIdle() { + return _rx_on_when_idle; + } + void setRebootOpenNetwork(uint8_t time); void openNetwork(uint8_t time); @@ -122,4 +144,4 @@ class ZigbeeCore { extern ZigbeeCore Zigbee; -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ZigbeeEP.cpp b/libraries/Zigbee/src/ZigbeeEP.cpp index 8597f4404c2..dbfe8596268 100644 --- a/libraries/Zigbee/src/ZigbeeEP.cpp +++ b/libraries/Zigbee/src/ZigbeeEP.cpp @@ -2,11 +2,13 @@ #include "ZigbeeEP.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "esp_zigbee_cluster.h" #include "zcl/esp_zigbee_zcl_power_config.h" +#define ZB_CMD_TIMEOUT 10000 // 10 seconds + bool ZigbeeEP::_is_bound = false; bool ZigbeeEP::_allow_multiple_binding = false; @@ -19,14 +21,12 @@ ZigbeeEP::ZigbeeEP(uint8_t endpoint) { _ep_config.endpoint = 0; _cluster_list = nullptr; _on_identify = nullptr; -#if !CONFIG_DISABLE_HAL_LOCKS if (!lock) { lock = xSemaphoreCreateBinary(); if (lock == NULL) { log_e("Semaphore creation failed"); } } -#endif } ZigbeeEP::~ZigbeeEP() {} @@ -104,7 +104,7 @@ void ZigbeeEP::reportBatteryPercentage() { 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_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID; - report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG; report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; @@ -114,13 +114,20 @@ void ZigbeeEP::reportBatteryPercentage() { log_v("Battery percentage reported"); } -char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) { +char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_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; + + if (short_addr != 0) { + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + } else { + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + } + 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[] = { @@ -132,22 +139,31 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) { // clear read manufacturer _read_manufacturer = nullptr; + esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); //Wait for response or timeout - if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) { + if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) { log_e("Error while reading manufacturer"); } return _read_manufacturer; } -char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr) { +char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_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; + + if (short_addr != 0) { + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr; + } else { + read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + } + 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[] = { @@ -159,11 +175,12 @@ char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr) { // clear read model _read_model = nullptr; + esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_read_attr_cmd_req(&read_req); + esp_zb_lock_release(); //Wait for response or timeout - //Semaphore take - if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) { + if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) { log_e("Error while reading model"); } return _read_model; @@ -173,8 +190,23 @@ 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); + log_i( + "Device on endpoint %d, short address: 0x%x, ieee address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", device->endpoint, device->short_addr, + device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], + device->ieee_addr[0] + ); + } +} + +void ZigbeeEP::printBoundDevices(Print &print) { + print.println("Bound devices:"); + for ([[maybe_unused]] + const auto &device : _bound_devices) { + print.printf( + "Device on endpoint %d, short address: 0x%x, ieee address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n", device->endpoint, device->short_addr, + device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], + device->ieee_addr[0] + ); } } @@ -210,4 +242,4 @@ void ZigbeeEP::zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message) { } } -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ZigbeeEP.h b/libraries/Zigbee/src/ZigbeeEP.h index 3a86617e2f4..522c84620ff 100644 --- a/libraries/Zigbee/src/ZigbeeEP.h +++ b/libraries/Zigbee/src/ZigbeeEP.h @@ -3,14 +3,12 @@ #pragma once #include "ZigbeeCore.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #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)); \ @@ -69,11 +67,13 @@ class ZigbeeEP { } void printBoundDevices(); + void printBoundDevices(Print &print); + std::list getBoundDevices() const { return _bound_devices; } - static bool isBound() { + static bool bound() { return _is_bound; } static void allowMultipleBinding(bool bind) { @@ -87,8 +87,8 @@ class ZigbeeEP { void reportBatteryPercentage(); // 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); + char *readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr); + char *readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr); bool epAllowMultipleBinding() { return _allow_multiple_binding; @@ -108,7 +108,6 @@ class ZigbeeEP { } private: - static bool _allow_multiple_binding; char *_read_manufacturer; char *_read_model; void (*_on_identify)(uint16_t time); @@ -119,11 +118,16 @@ class ZigbeeEP { esp_zb_endpoint_config_t _ep_config; esp_zb_cluster_list_t *_cluster_list; static bool _is_bound; + static bool _allow_multiple_binding; std::list _bound_devices; SemaphoreHandle_t lock; zb_power_source_t _power_source; + void addBoundDevice(zb_device_params_t *device) { + _bound_devices.push_back(device); + _is_bound = true; + } friend class ZigbeeCore; }; -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ZigbeeHandlers.cpp b/libraries/Zigbee/src/ZigbeeHandlers.cpp index 9522b0ba1a8..881d7ca0c37 100644 --- a/libraries/Zigbee/src/ZigbeeHandlers.cpp +++ b/libraries/Zigbee/src/ZigbeeHandlers.cpp @@ -2,7 +2,7 @@ #include "ZigbeeCore.h" #include "Arduino.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED // forward declaration of all implemented handlers static esp_err_t zb_attribute_set_handler(const esp_zb_zcl_set_attr_value_message_t *message); @@ -138,4 +138,4 @@ static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_m return ESP_OK; } -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp new file mode 100644 index 00000000000..89454c057e3 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp @@ -0,0 +1,109 @@ +#include "ZigbeeCarbonDioxideSensor.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +esp_zb_cluster_list_t *zigbee_carbon_dioxide_sensor_clusters_create(zigbee_carbon_dioxide_sensor_cfg_t *carbon_dioxide_sensor) { + esp_zb_basic_cluster_cfg_t *basic_cfg = carbon_dioxide_sensor ? &(carbon_dioxide_sensor->basic_cfg) : NULL; + esp_zb_identify_cluster_cfg_t *identify_cfg = carbon_dioxide_sensor ? &(carbon_dioxide_sensor->identify_cfg) : NULL; + esp_zb_carbon_dioxide_measurement_cluster_cfg_t *carbon_dioxide_meas_cfg = carbon_dioxide_sensor ? &(carbon_dioxide_sensor->carbon_dioxide_meas_cfg) : NULL; + esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(cluster_list, esp_zb_basic_cluster_create(basic_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(identify_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_carbon_dioxide_measurement_cluster( + cluster_list, esp_zb_carbon_dioxide_measurement_cluster_create(carbon_dioxide_meas_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_SERVER_ROLE); + return cluster_list; +} + +ZigbeeCarbonDioxideSensor::ZigbeeCarbonDioxideSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; + + //Create custom pressure sensor configuration + zigbee_carbon_dioxide_sensor_cfg_t carbon_dioxide_sensor_cfg = ZIGBEE_DEFAULT_CARBON_DIOXIDE_SENSOR_CONFIG(); + _cluster_list = zigbee_carbon_dioxide_sensor_clusters_create(&carbon_dioxide_sensor_cfg); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; +} + +void ZigbeeCarbonDioxideSensor::setMinMaxValue(float min, float max) { + float zb_min = min / 1000000.0f; + float zb_max = max / 1000000.0f; + esp_zb_attribute_list_t *carbon_dioxide_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_update_attr(carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MIN_MEASURED_VALUE_ID, (void *)&zb_min); + esp_zb_cluster_update_attr(carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MAX_MEASURED_VALUE_ID, (void *)&zb_max); +} + +void ZigbeeCarbonDioxideSensor::setTolerance(float tolerance) { + float zb_tolerance = tolerance / 1000000.0f; + esp_zb_attribute_list_t *carbon_dioxide_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_temperature_meas_cluster_add_attr(carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); +} + +void ZigbeeCarbonDioxideSensor::setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta) { + if (delta > 0) { + log_e("Delta reporting is currently not supported by the carbon dioxide sensor"); + } + // clang-format off + 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_CARBON_DIOXIDE_MEASUREMENT, + .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, + .attr_id = ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MEASURED_VALUE_ID, + .u = + { + .send_info = + { + .min_interval = min_interval, + .max_interval = max_interval, + .delta = + { + .u16 = delta, + }, + .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, + }; + // clang-format on + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); +} + +void ZigbeeCarbonDioxideSensor::setCarbonDioxide(float carbon_dioxide) { + float zb_carbon_dioxide = carbon_dioxide / 1000000.0f; + log_v("Updating carbon dioxide sensor value..."); + /* Update carbon dioxide sensor measured value */ + log_d("Setting carbon dioxide to %0.1f", carbon_dioxide); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MEASURED_VALUE_ID, + &zb_carbon_dioxide, false + ); + esp_zb_lock_release(); +} + +void ZigbeeCarbonDioxideSensor::report() { + /* 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_CARBON_DIOXIDE_MEASUREMENT_MEASURED_VALUE_ID; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_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("Carbon dioxide report sent"); +} + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h new file mode 100644 index 00000000000..71c353d4695 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h @@ -0,0 +1,61 @@ +/* Class of Zigbee Pressure sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +// clang-format off +#define ZIGBEE_DEFAULT_CARBON_DIOXIDE_SENSOR_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, \ + }, \ + .carbon_dioxide_meas_cfg = \ + { \ + .measured_value = 0.0, \ + .min_measured_value = 0.0, \ + .max_measured_value = 1.0, \ + }, \ + } +// clang-format on + +typedef struct zigbee_carbon_dioxide_sensor_cfg_s { + esp_zb_basic_cluster_cfg_t basic_cfg; + esp_zb_identify_cluster_cfg_t identify_cfg; + esp_zb_carbon_dioxide_measurement_cluster_cfg_t carbon_dioxide_meas_cfg; +} zigbee_carbon_dioxide_sensor_cfg_t; + +class ZigbeeCarbonDioxideSensor : public ZigbeeEP { +public: + ZigbeeCarbonDioxideSensor(uint8_t endpoint); + ~ZigbeeCarbonDioxideSensor(); + + // Set the carbon dioxide value in ppm + void setCarbonDioxide(float carbon_dioxide); + + // Set the min and max value for the carbon dioxide sensor in ppm + void setMinMaxValue(float min, float max); + + // Set the tolerance value for the carbon dioxide sensor in ppm + void setTolerance(float tolerance); + + // Set the reporting interval for carbon dioxide measurement in seconds and delta (carbon dioxide change in ppm) + // NOTE: Delta reporting is currently not supported by the carbon dioxide sensor + void setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta); + + // Report the carbon dioxide value + void report(); +}; + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp index 841d9c7f122..f034daba54a 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp @@ -1,5 +1,5 @@ #include "ZigbeeColorDimmableLight.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED ZigbeeColorDimmableLight::ZigbeeColorDimmableLight(uint8_t endpoint) : ZigbeeEP(endpoint) { _device_id = ESP_ZB_HA_COLOR_DIMMABLE_LIGHT_DEVICE_ID; @@ -47,6 +47,24 @@ void ZigbeeColorDimmableLight::calculateRGB(uint16_t x, uint16_t y, uint8_t &red blue = (uint8_t)(b * (float)255); } +void ZigbeeColorDimmableLight::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); +} + //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 @@ -109,4 +127,48 @@ void ZigbeeColorDimmableLight::lightChanged() { } } -#endif //SOC_IEEE802154_SUPPORTED +void ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue) { + //Update all attributes + _current_state = state; + _current_level = level; + _current_red = red; + _current_green = green; + _current_blue = blue; + lightChanged(); + + log_v("Updating on/off light state to %d", state); + /* Update light clusters */ + esp_zb_lock_acquire(portMAX_DELAY); + //set on/off state + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false + ); + //set level + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID, &_current_level, false + ); + //set color + uint16_t color_x, color_y; + calculateXY(red, green, blue, color_x, color_y); + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_X_ID, &color_x, false + ); + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_Y_ID, &color_y, false + ); + esp_zb_lock_release(); +} + +void ZigbeeColorDimmableLight::setLightState(bool state) { + setLight(state, _current_level, _current_red, _current_green, _current_blue); +} + +void ZigbeeColorDimmableLight::setLightLevel(uint8_t level) { + setLight(_current_state, level, _current_red, _current_green, _current_blue); +} + +void ZigbeeColorDimmableLight::setLightColor(uint8_t red, uint8_t green, uint8_t blue) { + setLight(_current_state, _current_level, red, green, blue); +} + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h index 992c2573654..9fa59dcfffc 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h @@ -3,7 +3,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_IEEE802154_SUPPORTED +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "ZigbeeEP.h" #include "ha/esp_zigbee_ha_standard.h" @@ -20,9 +21,31 @@ class ZigbeeColorDimmableLight : public ZigbeeEP { lightChanged(); } + void setLightState(bool state); + void setLightLevel(uint8_t level); + void setLightColor(uint8_t red, uint8_t green, uint8_t blue); + void setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue); + + bool getLightState() { + return _current_state; + } + uint8_t getLightLevel() { + return _current_level; + } + uint8_t getLightRed() { + return _current_red; + } + uint8_t getLightGreen() { + return _current_green; + } + uint8_t getLightBlue() { + return _current_blue; + } + 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); + void calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y); uint16_t getCurrentColorX(); uint16_t getCurrentColorY(); @@ -38,4 +61,4 @@ class ZigbeeColorDimmableLight : public ZigbeeEP { uint16_t _current_blue; }; -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp index d9a9e1c1014..4fd492a5477 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp @@ -1,5 +1,5 @@ #include "ZigbeeColorDimmerSwitch.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED // Initialize the static instance pointer ZigbeeColorDimmerSwitch *ZigbeeColorDimmerSwitch::_instance = nullptr; @@ -98,10 +98,10 @@ void ZigbeeColorDimmerSwitch::lightToggle() { 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); + log_v("Sending 'light toggle' command"); + esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_on_off_cmd_req(&cmd_req); - //esp_zb_lock_release(); + esp_zb_lock_release(); } else { log_e("Light not bound"); } @@ -114,7 +114,7 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint16_t group_addr) { 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); + log_v("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(); @@ -131,7 +131,27 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) 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); + log_v("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::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_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.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; + memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + log_v( + "Sending 'light toggle' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5], + ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_on_off_cmd_req(&cmd_req); esp_zb_lock_release(); @@ -146,7 +166,7 @@ void ZigbeeColorDimmerSwitch::lightOn() { 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"); + log_v("Sending 'light on' command"); esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_on_off_cmd_req(&cmd_req); esp_zb_lock_release(); @@ -162,7 +182,7 @@ void ZigbeeColorDimmerSwitch::lightOn(uint16_t group_addr) { 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); + log_v("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(); @@ -179,7 +199,27 @@ void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) { 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); + log_v("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::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_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.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; + memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + log_v( + "Sending 'light on' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5], + ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_on_off_cmd_req(&cmd_req); esp_zb_lock_release(); @@ -194,7 +234,7 @@ void ZigbeeColorDimmerSwitch::lightOff() { 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"); + log_v("Sending 'light off' command"); esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_on_off_cmd_req(&cmd_req); esp_zb_lock_release(); @@ -210,7 +250,7 @@ void ZigbeeColorDimmerSwitch::lightOff(uint16_t group_addr) { 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); + log_v("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(); @@ -227,7 +267,27 @@ void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) { 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); + log_v("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::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_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.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; + memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + log_v( + "Sending 'light off' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5], + ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_on_off_cmd_req(&cmd_req); esp_zb_lock_release(); @@ -243,7 +303,7 @@ void ZigbeeColorDimmerSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effe 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"); + log_v("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(); @@ -257,7 +317,7 @@ void ZigbeeColorDimmerSwitch::lightOnWithSceneRecall() { 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"); + log_v("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(); @@ -274,7 +334,7 @@ void ZigbeeColorDimmerSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16 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"); + log_v("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(); @@ -290,7 +350,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level) { 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"); + log_v("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(); @@ -307,7 +367,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint16_t 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); + log_v("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(); @@ -325,7 +385,28 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, uin 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); + log_v("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::setLightLevel(uint8_t level, uint8_t endpoint, esp_zb_ieee_addr_t ieee_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.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + cmd_req.level = level; + cmd_req.transition_time = 0xffff; + log_v( + "Sending 'set light level' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], + ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_level_move_to_level_cmd_req(&cmd_req); esp_zb_lock_release(); @@ -346,7 +427,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t cmd_req.color_x = color_x; cmd_req.color_y = color_y; cmd_req.transition_time = 0; - log_i("Sending 'set light color' command"); + log_v("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(); @@ -368,7 +449,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t 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); + log_v("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(); @@ -391,7 +472,33 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t 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); + log_v("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"); + } +} + +void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, esp_zb_ieee_addr_t ieee_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.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + cmd_req.color_x = color_x; + cmd_req.color_y = color_y; + cmd_req.transition_time = 0; + log_v( + "Sending 'set light color' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], + ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_color_move_to_color_cmd_req(&cmd_req); esp_zb_lock_release(); @@ -400,4 +507,4 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t } } -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h index 2263f3235ca..8e2a4d9e1a3 100644 --- a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h +++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h @@ -3,7 +3,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_IEEE802154_SUPPORTED +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "ZigbeeEP.h" #include "ha/esp_zigbee_ha_standard.h" @@ -17,14 +18,17 @@ class ZigbeeColorDimmerSwitch : public ZigbeeEP { void lightToggle(); void lightToggle(uint16_t group_addr); void lightToggle(uint8_t endpoint, uint16_t short_addr); + void lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr); void lightOn(); void lightOn(uint16_t group_addr); void lightOn(uint8_t endpoint, uint16_t short_addr); + void lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr); void lightOff(); void lightOff(uint16_t group_addr); void lightOff(uint8_t endpoint, uint16_t short_addr); + void lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_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); @@ -33,18 +37,12 @@ class ZigbeeColorDimmerSwitch : public ZigbeeEP { 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 setLightLevel(uint8_t level, uint8_t endpoint, esp_zb_ieee_addr_t ieee_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); + void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr); private: // save instance of the class in order to use it in static functions @@ -57,4 +55,4 @@ class ZigbeeColorDimmerSwitch : public ZigbeeEP { void calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y); }; -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeDimmableLight.cpp b/libraries/Zigbee/src/ep/ZigbeeDimmableLight.cpp new file mode 100644 index 00000000000..00d3aac3752 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeDimmableLight.cpp @@ -0,0 +1,103 @@ + +#include "ZigbeeDimmableLight.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +#include "esp_zigbee_cluster.h" + +ZigbeeDimmableLight::ZigbeeDimmableLight(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_DIMMABLE_LIGHT_DEVICE_ID; + + zigbee_dimmable_light_cfg_t light_cfg = ZIGBEE_DEFAULT_DIMMABLE_LIGHT_CONFIG(); + _cluster_list = zigbee_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_DIMMABLE_LIGHT_DEVICE_ID, .app_device_version = 0}; + + // set default values + _current_state = false; + _current_level = 255; +} + +// set attribute method -> method overridden in child class +void ZigbeeDimmableLight::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 { + log_w("Received message ignored. Cluster ID: %d not supported for dimmable Light", message->info.cluster); + } +} + +void ZigbeeDimmableLight::lightChanged() { + if (_on_light_change) { + _on_light_change(_current_state, _current_level); + } +} + +void ZigbeeDimmableLight::setLight(bool state, uint8_t level) { + // Update all attributes + _current_state = state; + _current_level = level; + lightChanged(); + + log_v("Updating on/off light state to %d", state); + /* Update light clusters */ + esp_zb_lock_acquire(portMAX_DELAY); + // set on/off state + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false + ); + // set level + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID, &_current_level, false + ); + esp_zb_lock_release(); +} + +void ZigbeeDimmableLight::setLightState(bool state) { + setLight(state, _current_level); +} + +void ZigbeeDimmableLight::setLightLevel(uint8_t level) { + setLight(_current_state, level); +} + +esp_zb_cluster_list_t *ZigbeeDimmableLight::zigbee_dimmable_light_clusters_create(zigbee_dimmable_light_cfg_t *light_cfg) { + esp_zb_attribute_list_t *esp_zb_basic_cluster = esp_zb_basic_cluster_create(&light_cfg->basic_cfg); + esp_zb_attribute_list_t *esp_zb_identify_cluster = esp_zb_identify_cluster_create(&light_cfg->identify_cfg); + esp_zb_attribute_list_t *esp_zb_groups_cluster = esp_zb_groups_cluster_create(&light_cfg->groups_cfg); + esp_zb_attribute_list_t *esp_zb_scenes_cluster = esp_zb_scenes_cluster_create(&light_cfg->scenes_cfg); + esp_zb_attribute_list_t *esp_zb_on_off_cluster = esp_zb_on_off_cluster_create(&light_cfg->on_off_cfg); + esp_zb_attribute_list_t *esp_zb_level_cluster = esp_zb_level_cluster_create(&light_cfg->level_cfg); + + // ------------------------------ Create cluster list ------------------------------ + esp_zb_cluster_list_t *esp_zb_cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(esp_zb_cluster_list, esp_zb_basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(esp_zb_cluster_list, esp_zb_identify_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_groups_cluster(esp_zb_cluster_list, esp_zb_groups_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_scenes_cluster(esp_zb_cluster_list, esp_zb_scenes_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_on_off_cluster(esp_zb_cluster_list, esp_zb_on_off_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_level_cluster(esp_zb_cluster_list, esp_zb_level_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + + return esp_zb_cluster_list; +} + +#endif // SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeDimmableLight.h b/libraries/Zigbee/src/ep/ZigbeeDimmableLight.h new file mode 100644 index 00000000000..034c34899b4 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeDimmableLight.h @@ -0,0 +1,113 @@ +/* Class of Zigbee On/Off Light endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +/** + * @brief Zigbee HA standard dimmable light device clusters. + * Added here as not supported by ESP Zigbee library. + * + * + */ +typedef struct zigbee_dimmable_light_cfg_s { + esp_zb_basic_cluster_cfg_t basic_cfg; /*!< Basic cluster configuration, @ref esp_zb_basic_cluster_cfg_s */ + esp_zb_identify_cluster_cfg_t identify_cfg; /*!< Identify cluster configuration, @ref esp_zb_identify_cluster_cfg_s */ + esp_zb_groups_cluster_cfg_t groups_cfg; /*!< Groups cluster configuration, @ref esp_zb_groups_cluster_cfg_s */ + esp_zb_scenes_cluster_cfg_t scenes_cfg; /*!< Scenes cluster configuration, @ref esp_zb_scenes_cluster_cfg_s */ + esp_zb_on_off_cluster_cfg_t on_off_cfg; /*!< On off cluster configuration, @ref esp_zb_on_off_cluster_cfg_s */ + esp_zb_level_cluster_cfg_t level_cfg; /*!< Level cluster configuration, @ref esp_zb_level_cluster_cfg_s */ +} zigbee_dimmable_light_cfg_t; + +/** + * @brief Zigbee HA standard dimmable light device default config value. + * Added here as not supported by ESP Zigbee library. + * + */ +// clang-format off +#define ZIGBEE_DEFAULT_DIMMABLE_LIGHT_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, \ + }, \ + .groups_cfg = \ + { \ + .groups_name_support_id = ESP_ZB_ZCL_GROUPS_NAME_SUPPORT_DEFAULT_VALUE, \ + }, \ + .scenes_cfg = \ + { \ + .scenes_count = ESP_ZB_ZCL_SCENES_SCENE_COUNT_DEFAULT_VALUE, \ + .current_scene = ESP_ZB_ZCL_SCENES_CURRENT_SCENE_DEFAULT_VALUE, \ + .current_group = ESP_ZB_ZCL_SCENES_CURRENT_GROUP_DEFAULT_VALUE, \ + .scene_valid = ESP_ZB_ZCL_SCENES_SCENE_VALID_DEFAULT_VALUE, \ + .name_support = ESP_ZB_ZCL_SCENES_NAME_SUPPORT_DEFAULT_VALUE, \ + }, \ + .on_off_cfg = \ + { \ + .on_off = ESP_ZB_ZCL_ON_OFF_ON_OFF_DEFAULT_VALUE, \ + }, \ + .level_cfg = \ + { \ + .current_level = ESP_ZB_ZCL_LEVEL_CONTROL_CURRENT_LEVEL_DEFAULT_VALUE, \ + }, \ + } +// clang-format on + +class ZigbeeDimmableLight : public ZigbeeEP { +public: + ZigbeeDimmableLight(uint8_t endpoint); + ~ZigbeeDimmableLight(); + + void onLightChange(void (*callback)(bool, uint8_t)) { + _on_light_change = callback; + } + void restoreLight() { + lightChanged(); + } + + void setLightState(bool state); + void setLightLevel(uint8_t level); + void setLight(bool state, uint8_t level); + + bool getLightState() { + return _current_state; + } + uint8_t getLightLevel() { + return _current_level; + } + +private: + void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; + + void lightChanged(); + // callback function to be called on light change (State, Level) + void (*_on_light_change)(bool, uint8_t); + + /** + * @brief Create a standard HA dimmable light cluster list. + * Added here as not supported by ESP Zigbee library. + * + * @note This contains basic, identify, groups, scenes, on-off, level, as server side. + * @param[in] light_cfg Configuration parameters for this cluster lists defined by @ref zigbee_dimmable_light_cfg_t + * + * @return Pointer to cluster list @ref esp_zb_cluster_list_s + * + */ + esp_zb_cluster_list_t *zigbee_dimmable_light_clusters_create(zigbee_dimmable_light_cfg_t *light_cfg); + + bool _current_state; + uint8_t _current_level; +}; + +#endif // SOC_IEEE802154_SUPPORTED diff --git a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp new file mode 100644 index 00000000000..6adf8172194 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp @@ -0,0 +1,104 @@ +#include "ZigbeeFlowSensor.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +esp_zb_cluster_list_t *zigbee_flow_sensor_clusters_create(zigbee_flow_sensor_cfg_t *flow_sensor) { + esp_zb_basic_cluster_cfg_t *basic_cfg = flow_sensor ? &(flow_sensor->basic_cfg) : NULL; + esp_zb_identify_cluster_cfg_t *identify_cfg = flow_sensor ? &(flow_sensor->identify_cfg) : NULL; + esp_zb_flow_meas_cluster_cfg_t *flow_meas_cfg = flow_sensor ? &(flow_sensor->flow_meas_cfg) : NULL; + esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(cluster_list, esp_zb_basic_cluster_create(basic_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(identify_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_flow_meas_cluster(cluster_list, esp_zb_flow_meas_cluster_create(flow_meas_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_SERVER_ROLE); + return cluster_list; +} + +ZigbeeFlowSensor::ZigbeeFlowSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; + + //Create custom pressure sensor configuration + zigbee_flow_sensor_cfg_t flow_sensor_cfg = ZIGBEE_DEFAULT_FLOW_SENSOR_CONFIG(); + _cluster_list = zigbee_flow_sensor_clusters_create(&flow_sensor_cfg); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; +} + +void ZigbeeFlowSensor::setMinMaxValue(float min, float max) { + uint16_t zb_min = (uint16_t)(min * 10); + uint16_t zb_max = (uint16_t)(max * 10); + esp_zb_attribute_list_t *flow_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_FLOW_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_update_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_MIN_VALUE_ID, (void *)&zb_min); + esp_zb_cluster_update_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_MAX_VALUE_ID, (void *)&zb_max); +} + +void ZigbeeFlowSensor::setTolerance(float tolerance) { + // Convert tolerance to ZCL uint16_t + uint16_t zb_tolerance = (uint16_t)(tolerance * 10); + esp_zb_attribute_list_t *flow_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_FLOW_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_flow_meas_cluster_add_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_TOLERANCE_ID, (void *)&zb_tolerance); +} + +void ZigbeeFlowSensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) { + // clang-format off + 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_FLOW_MEASUREMENT, + .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, + .attr_id = ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_VALUE_ID, + .u = + { + .send_info = + { + .min_interval = min_interval, + .max_interval = max_interval, + .delta = + { + .u16 = (uint16_t)(delta * 10), // 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, + }; + // clang-format on + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); +} + +void ZigbeeFlowSensor::setFlow(float flow) { + uint16_t zb_flow = (uint16_t)(flow * 10); + log_v("Updating flow sensor value..."); + /* Update temperature sensor measured value */ + log_d("Setting flow to %d", zb_flow); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_FLOW_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_VALUE_ID, &zb_flow, false + ); + esp_zb_lock_release(); +} + +void ZigbeeFlowSensor::report() { + /* 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_FLOW_MEASUREMENT_VALUE_ID; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_FLOW_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("Flow report sent"); +} + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h new file mode 100644 index 00000000000..3514e2fcc1b --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h @@ -0,0 +1,60 @@ +/* Class of Zigbee Flow sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +// clang-format off +#define ZIGBEE_DEFAULT_FLOW_SENSOR_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, \ + }, \ + .flow_meas_cfg = \ + { \ + .measured_value = 0, \ + .min_value = 0, \ + .max_value = 0x7FFF, \ + }, \ + } +// clang-format on + +typedef struct zigbee_flow_sensor_cfg_s { + esp_zb_basic_cluster_cfg_t basic_cfg; + esp_zb_identify_cluster_cfg_t identify_cfg; + esp_zb_flow_meas_cluster_cfg_t flow_meas_cfg; +} zigbee_flow_sensor_cfg_t; + +class ZigbeeFlowSensor : public ZigbeeEP { +public: + ZigbeeFlowSensor(uint8_t endpoint); + ~ZigbeeFlowSensor(); + + // Set the flow value in 0,1 m3/h + void setFlow(float value); + + // Set the min and max value for the flow sensor in 0,1 m3/h + void setMinMaxValue(float min, float max); + + // Set the tolerance value for the flow sensor in 0,01 m3/h + void setTolerance(float tolerance); + + // Set the reporting interval for flow measurement in seconds and delta (temp change in 0,1 m3/h) + void setReporting(uint16_t min_interval, uint16_t max_interval, float delta); + + // Report the flow value + void report(); +}; + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeLight.cpp b/libraries/Zigbee/src/ep/ZigbeeLight.cpp index 1f59cd82325..100efe34a86 100644 --- a/libraries/Zigbee/src/ep/ZigbeeLight.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeLight.cpp @@ -1,5 +1,5 @@ #include "ZigbeeLight.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED ZigbeeLight::ZigbeeLight(uint8_t endpoint) : ZigbeeEP(endpoint) { _device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID; @@ -33,4 +33,17 @@ void ZigbeeLight::lightChanged() { } } -#endif //SOC_IEEE802154_SUPPORTED +void ZigbeeLight::setLight(bool state) { + _current_state = state; + lightChanged(); + + log_v("Updating on/off light state to %d", state); + /* Update on/off light state */ + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false + ); + esp_zb_lock_release(); +} + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeLight.h b/libraries/Zigbee/src/ep/ZigbeeLight.h index 32e4e8c9bdc..9b8fc409d4a 100644 --- a/libraries/Zigbee/src/ep/ZigbeeLight.h +++ b/libraries/Zigbee/src/ep/ZigbeeLight.h @@ -3,7 +3,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_IEEE802154_SUPPORTED +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "ZigbeeEP.h" #include "ha/esp_zigbee_ha_standard.h" @@ -13,13 +14,20 @@ class ZigbeeLight : public ZigbeeEP { ZigbeeLight(uint8_t endpoint); ~ZigbeeLight(); - // Use tp set a cb function to be called on light change + // Use to set a cb function to be called on light change void onLightChange(void (*callback)(bool)) { _on_light_change = callback; } + // Use to restore light state void restoreLight() { lightChanged(); } + // Use to control light state + void setLight(bool state); + // Use to get light state + bool getLightState() { + return _current_state; + } private: void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override; @@ -30,4 +38,4 @@ class ZigbeeLight : public ZigbeeEP { bool _current_state; }; -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp b/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp new file mode 100644 index 00000000000..3a7acee040c --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp @@ -0,0 +1,60 @@ +#include "ZigbeeOccupancySensor.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +esp_zb_cluster_list_t *zigbee_occupancy_sensor_clusters_create(zigbee_occupancy_sensor_cfg_t *occupancy_sensor) { + esp_zb_basic_cluster_cfg_t *basic_cfg = occupancy_sensor ? &(occupancy_sensor->basic_cfg) : NULL; + esp_zb_identify_cluster_cfg_t *identify_cfg = occupancy_sensor ? &(occupancy_sensor->identify_cfg) : NULL; + esp_zb_occupancy_sensing_cluster_cfg_t *occupancy_meas_cfg = occupancy_sensor ? &(occupancy_sensor->occupancy_meas_cfg) : NULL; + esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(cluster_list, esp_zb_basic_cluster_create(basic_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(identify_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_occupancy_sensing_cluster(cluster_list, esp_zb_occupancy_sensing_cluster_create(occupancy_meas_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_SERVER_ROLE); + return cluster_list; +} + +ZigbeeOccupancySensor::ZigbeeOccupancySensor(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; + + //Create custom occupancy sensor configuration + zigbee_occupancy_sensor_cfg_t occupancy_sensor_cfg = ZIGBEE_DEFAULT_OCCUPANCY_SENSOR_CONFIG(); + _cluster_list = zigbee_occupancy_sensor_clusters_create(&occupancy_sensor_cfg); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; +} + +void ZigbeeOccupancySensor::setSensorType(uint8_t sensor_type) { + uint8_t sensor_type_bitmap = 1 << sensor_type; + esp_zb_attribute_list_t *occupancy_sens_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_ID, (void *)&sensor_type); + esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_BITMAP_ID, (void *)&sensor_type_bitmap); +} + +void ZigbeeOccupancySensor::setOccupancy(bool occupied) { + log_v("Updating occupancy sensor value..."); + /* Update occupancy sensor value */ + log_d("Setting occupancy to %d", occupied); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_ID, &occupied, false + ); + esp_zb_lock_release(); +} + +void ZigbeeOccupancySensor::report() { + /* 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_OCCUPANCY_SENSING_OCCUPANCY_ID; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING; + 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("Occupancy report sent"); +} + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.h b/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.h new file mode 100644 index 00000000000..e4b25c063e5 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeeOccupancySensor.h @@ -0,0 +1,54 @@ +/* Class of Zigbee Pressure sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +// clang-format off +#define ZIGBEE_DEFAULT_OCCUPANCY_SENSOR_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, \ + }, \ + .occupancy_meas_cfg = \ + { \ + .occupancy = ESP_ZB_ZCL_OCCUPANCY_SENSING_OCCUPANCY_UNOCCUPIED, \ + .sensor_type = ESP_ZB_ZCL_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_PIR, \ + .sensor_type_bitmap = (1 << ESP_ZB_ZCL_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_PIR), \ + }, \ + } +// clang-format on + +typedef struct zigbee_occupancy_sensor_cfg_s { + esp_zb_basic_cluster_cfg_t basic_cfg; + esp_zb_identify_cluster_cfg_t identify_cfg; + esp_zb_occupancy_sensing_cluster_cfg_t occupancy_meas_cfg; +} zigbee_occupancy_sensor_cfg_t; + +class ZigbeeOccupancySensor : public ZigbeeEP { +public: + ZigbeeOccupancySensor(uint8_t endpoint); + ~ZigbeeOccupancySensor(); + + // Set the occupancy value. True for occupied, false for unoccupied + void setOccupancy(bool occupied); + + // Set the sensor type, see esp_zb_zcl_occupancy_sensing_occupancy_sensor_type_t + void setSensorType(uint8_t sensor_type); + + // Report the occupancy value + void report(); +}; + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp b/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp new file mode 100644 index 00000000000..9415502215d --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp @@ -0,0 +1,100 @@ +#include "ZigbeePressureSensor.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +esp_zb_cluster_list_t *zigbee_pressure_sensor_clusters_create(zigbee_pressure_sensor_cfg_t *pressure_sensor) { + esp_zb_basic_cluster_cfg_t *basic_cfg = pressure_sensor ? &(pressure_sensor->basic_cfg) : NULL; + esp_zb_identify_cluster_cfg_t *identify_cfg = pressure_sensor ? &(pressure_sensor->identify_cfg) : NULL; + esp_zb_pressure_meas_cluster_cfg_t *pressure_meas_cfg = pressure_sensor ? &(pressure_sensor->pressure_meas_cfg) : NULL; + esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create(); + esp_zb_cluster_list_add_basic_cluster(cluster_list, esp_zb_basic_cluster_create(basic_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(identify_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_list_add_pressure_meas_cluster(cluster_list, esp_zb_pressure_meas_cluster_create(pressure_meas_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_SERVER_ROLE); + return cluster_list; +} + +ZigbeePressureSensor::ZigbeePressureSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { + _device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID; + + //Create custom pressure sensor configuration + zigbee_pressure_sensor_cfg_t presssure_sensor_cfg = ZIGBEE_DEFAULT_PRESSURE_SENSOR_CONFIG(); + _cluster_list = zigbee_pressure_sensor_clusters_create(&presssure_sensor_cfg); + + _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; +} + +void ZigbeePressureSensor::setMinMaxValue(int16_t min, int16_t max) { + + esp_zb_attribute_list_t *pressure_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_cluster_update_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_MIN_VALUE_ID, (void *)&min); + esp_zb_cluster_update_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_MAX_VALUE_ID, (void *)&max); +} + +void ZigbeePressureSensor::setTolerance(uint16_t tolerance) { + esp_zb_attribute_list_t *pressure_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_zb_temperature_meas_cluster_add_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_TOLERANCE_ID, (void *)&tolerance); +} + +void ZigbeePressureSensor::setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta) { + // clang-format off + 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_PRESSURE_MEASUREMENT, + .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, + .attr_id = ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_VALUE_ID, + .u = + { + .send_info = + { + .min_interval = min_interval, + .max_interval = max_interval, + .delta = + { + .u16 = delta, // x hPa + }, + .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, + }; + // clang-format on + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); +} + +void ZigbeePressureSensor::setPressure(int16_t pressure) { + log_v("Updating pressure sensor value..."); + /* Update temperature sensor measured value */ + log_d("Setting pressure to %d hPa", pressure); + esp_zb_lock_acquire(portMAX_DELAY); + esp_zb_zcl_set_attribute_val( + _endpoint, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_VALUE_ID, &pressure, false + ); + esp_zb_lock_release(); +} + +void ZigbeePressureSensor::report() { + /* 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_PRESSURE_MEASUREMENT_VALUE_ID; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; + report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_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("Pressure report sent"); +} + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeePressureSensor.h b/libraries/Zigbee/src/ep/ZigbeePressureSensor.h new file mode 100644 index 00000000000..f088c033bb9 --- /dev/null +++ b/libraries/Zigbee/src/ep/ZigbeePressureSensor.h @@ -0,0 +1,60 @@ +/* Class of Zigbee Pressure sensor endpoint inherited from common EP class */ + +#pragma once + +#include "soc/soc_caps.h" +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED + +#include "ZigbeeEP.h" +#include "ha/esp_zigbee_ha_standard.h" + +// clang-format off +#define ZIGBEE_DEFAULT_PRESSURE_SENSOR_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, \ + }, \ + .pressure_meas_cfg = \ + { \ + .measured_value = ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_VALUE_DEFAULT_VALUE, \ + .min_value = ESP_ZB_ZCL_PATTR_RESSURE_MEASUREMENT_MIN_VALUE_DEFAULT_VALUE, \ + .max_value = ESP_ZB_ZCL_PATTR_RESSURE_MEASUREMENT_MAX_VALUE_DEFAULT_VALUE, \ + }, \ + } +// clang-format on + +typedef struct zigbee_pressure_sensor_cfg_s { + esp_zb_basic_cluster_cfg_t basic_cfg; + esp_zb_identify_cluster_cfg_t identify_cfg; + esp_zb_pressure_meas_cluster_cfg_t pressure_meas_cfg; +} zigbee_pressure_sensor_cfg_t; + +class ZigbeePressureSensor : public ZigbeeEP { +public: + ZigbeePressureSensor(uint8_t endpoint); + ~ZigbeePressureSensor(); + + // Set the pressure value in 1 hPa + void setPressure(int16_t value); + + // Set the min and max value for the pressure sensor in 1 hPa + void setMinMaxValue(int16_t min, int16_t max); + + // Set the tolerance value for the pressure sensor in 1 hPa + void setTolerance(uint16_t tolerance); + + // Set the reporting interval for pressure measurement in seconds and delta (pressure change in 1 hPa) + void setReporting(uint16_t min_interval, uint16_t max_interval, uint16_t delta); + + // Report the pressure value + void report(); +}; + +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp index 17f0b6703c9..f6b36d7f0d4 100644 --- a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp @@ -1,5 +1,5 @@ #include "ZigbeeSwitch.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED // Initialize the static instance pointer ZigbeeSwitch *ZigbeeSwitch::_instance = nullptr; @@ -59,7 +59,6 @@ void ZigbeeSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) { .num_out_clusters = 1, .cluster_list = cluster_list, }; - esp_zb_zdo_match_cluster(&on_off_req, findCb, &_endpoint); } @@ -70,8 +69,10 @@ void ZigbeeSwitch::lightToggle() { 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"); + log_v("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"); } @@ -84,8 +85,10 @@ void ZigbeeSwitch::lightToggle(uint16_t group_addr) { 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); + log_v("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"); } @@ -99,8 +102,30 @@ void ZigbeeSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) { 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); + log_v("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 ZigbeeSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_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.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; + memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + log_v( + "Sending 'light toggle' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5], + ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); + 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"); } @@ -112,8 +137,10 @@ void ZigbeeSwitch::lightOn() { 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"); + log_v("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"); } @@ -126,8 +153,10 @@ void ZigbeeSwitch::lightOn(uint16_t group_addr) { 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); + log_v("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"); } @@ -141,8 +170,30 @@ void ZigbeeSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) { 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); + log_v("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 ZigbeeSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_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.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID; + memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + log_v( + "Sending 'light on' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5], + ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); + 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"); } @@ -154,8 +205,10 @@ void ZigbeeSwitch::lightOff() { 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"); + log_v("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"); } @@ -168,8 +221,10 @@ void ZigbeeSwitch::lightOff(uint16_t group_addr) { 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); + log_v("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"); } @@ -183,8 +238,30 @@ void ZigbeeSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) { 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); + log_v("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 ZigbeeSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_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.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT; + cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID; + memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t)); + log_v( + "Sending 'light off' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5], + ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0] + ); + 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"); } @@ -197,8 +274,10 @@ void ZigbeeSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) 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"); + log_v("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"); } @@ -209,8 +288,10 @@ void ZigbeeSwitch::lightOnWithSceneRecall() { 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"); + log_v("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"); } @@ -223,11 +304,13 @@ void ZigbeeSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, 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"); + log_v("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"); } } -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.h b/libraries/Zigbee/src/ep/ZigbeeSwitch.h index bbc6c0a91dc..62264641378 100644 --- a/libraries/Zigbee/src/ep/ZigbeeSwitch.h +++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.h @@ -3,7 +3,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_IEEE802154_SUPPORTED +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "ZigbeeEP.h" #include "ha/esp_zigbee_ha_standard.h" @@ -17,14 +18,17 @@ class ZigbeeSwitch : public ZigbeeEP { void lightToggle(); void lightToggle(uint16_t group_addr); void lightToggle(uint8_t endpoint, uint16_t short_addr); + void lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr); void lightOn(); void lightOn(uint16_t group_addr); void lightOn(uint8_t endpoint, uint16_t short_addr); + void lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr); void lightOff(); void lightOff(uint16_t group_addr); void lightOff(uint8_t endpoint, uint16_t short_addr); + void lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_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); @@ -39,4 +43,4 @@ class ZigbeeSwitch : public ZigbeeEP { static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx); }; -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp index a20f6255746..98a3793fbad 100644 --- a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp @@ -1,8 +1,9 @@ #include "ZigbeeTempSensor.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED ZigbeeTempSensor::ZigbeeTempSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { _device_id = ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID; + _humidity_sensor = false; 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); @@ -60,7 +61,9 @@ void ZigbeeTempSensor::setReporting(uint16_t min_interval, uint16_t max_interval }, .manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC, }; + esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); } void ZigbeeTempSensor::setTemperature(float temperature) { @@ -80,7 +83,7 @@ void ZigbeeTempSensor::reportTemperature() { 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.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT; report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; @@ -101,6 +104,7 @@ void ZigbeeTempSensor::addHumiditySensor(float min, float max, float tolerance) esp_zb_humidity_meas_cluster_add_attr(humidity_cluster, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_MAX_VALUE_ID, &zb_max); esp_zb_humidity_meas_cluster_add_attr(humidity_cluster, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_TOLERANCE_ID, &zb_tolerance); esp_zb_cluster_list_add_humidity_meas_cluster(_cluster_list, humidity_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + _humidity_sensor = true; } void ZigbeeTempSensor::setHumidity(float humidity) { @@ -121,7 +125,7 @@ void ZigbeeTempSensor::reportHumidity() { 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_REL_HUMIDITY_MEASUREMENT_VALUE_ID; - report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE; + report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI; report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT; report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint; @@ -158,7 +162,16 @@ void ZigbeeTempSensor::setHumidityReporting(uint16_t min_interval, uint16_t max_ }, .manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC, }; + esp_zb_lock_acquire(portMAX_DELAY); esp_zb_zcl_update_reporting_info(&reporting_info); + esp_zb_lock_release(); +} + +void ZigbeeTempSensor::report() { + reportTemperature(); + if (_humidity_sensor) { + reportHumidity(); + } } -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h index 0f2040ff917..2951d4b7628 100644 --- a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h @@ -3,7 +3,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_IEEE802154_SUPPORTED +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "ZigbeeEP.h" #include "ha/esp_zigbee_ha_standard.h" @@ -39,6 +40,12 @@ class ZigbeeTempSensor : public ZigbeeEP { // Report the humidity value void reportHumidity(); + + // Report the temperature and humidity values if humidity sensor is added + void report(); + +private: + bool _humidity_sensor; }; -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp index b9805a37a19..4610e087563 100644 --- a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp @@ -1,5 +1,5 @@ #include "ZigbeeThermostat.h" -#if SOC_IEEE802154_SUPPORTED +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED static float zb_s16_to_temperature(int16_t value) { return 1.0 * value / 100; @@ -185,7 +185,7 @@ void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t m int16_t report_change = (int16_t)delta * 100; esp_zb_zcl_config_report_record_t records[] = { { - .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV, + .direction = ESP_ZB_ZCL_REPORT_DIRECTION_SEND, .attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, .attrType = ESP_ZB_ZCL_ATTR_TYPE_S16, .min_interval = min_interval, @@ -202,4 +202,4 @@ void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t m esp_zb_lock_release(); } -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.h b/libraries/Zigbee/src/ep/ZigbeeThermostat.h index 7d63cd9f726..fe797ffd7b6 100644 --- a/libraries/Zigbee/src/ep/ZigbeeThermostat.h +++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.h @@ -3,7 +3,8 @@ #pragma once #include "soc/soc_caps.h" -#if SOC_IEEE802154_SUPPORTED +#include "sdkconfig.h" +#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED #include "ZigbeeEP.h" #include "ha/esp_zigbee_ha_standard.h" @@ -61,4 +62,4 @@ class ZigbeeThermostat : public ZigbeeEP { void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) override; }; -#endif //SOC_IEEE802154_SUPPORTED +#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED diff --git a/package.json b/package.json index 6dbb69ad305..e13a446bd98 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "framework-arduinoespressif32", - "version": "3.0.5", - "description": "Arduino Wiring-based Framework for the Espressif ESP32, ESP32-S and ESP32-C series of SoCs", + "version": "3.1.0", + "description": "Arduino Wiring-based Framework for the Espressif ESP32, ESP32-P4, ESP32-S and ESP32-C series of SoCs", "keywords": [ "framework", "arduino", diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 751617ee152..310c28fad7d 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -42,47 +42,37 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.1-33fbade6" + "version": "idf-release_v5.3-083aad99-v2" }, { "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-20240821" + "version": "v0.12.0-esp32-20241016" }, { "packager": "esp32", "name": "esptool_py", - "version": "4.6" + "version": "4.9.dev3" }, { "packager": "esp32", @@ -105,545 +95,421 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.1-33fbade6", + "version": "idf-release_v5.3-083aad99-v2", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d", - "size": "309285463" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "checksum": "SHA-256:4c6cae2e34df7e85a149615a6c18169777faf9460f708fc51d93616a117973c2", + "size": "341175680" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d", - "size": "309285463" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "checksum": "SHA-256:4c6cae2e34df7e85a149615a6c18169777faf9460f708fc51d93616a117973c2", + "size": "341175680" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d", - "size": "309285463" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "checksum": "SHA-256:4c6cae2e34df7e85a149615a6c18169777faf9460f708fc51d93616a117973c2", + "size": "341175680" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d", - "size": "309285463" - }, - { - "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d", - "size": "309285463" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "checksum": "SHA-256:4c6cae2e34df7e85a149615a6c18169777faf9460f708fc51d93616a117973c2", + "size": "341175680" }, - { - "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d", - "size": "309285463" - }, - { - "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d", - "size": "309285463" - }, - { - "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip", - "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d", - "size": "309285463" - } - ] - }, - { - "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" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "checksum": "SHA-256:4c6cae2e34df7e85a149615a6c18169777faf9460f708fc51d93616a117973c2", + "size": "341175680" }, { "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-083aad99-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "checksum": "SHA-256:4c6cae2e34df7e85a149615a6c18169777faf9460f708fc51d93616a117973c2", + "size": "341175680" }, { "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-083aad99-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "checksum": "SHA-256:4c6cae2e34df7e85a149615a6c18169777faf9460f708fc51d93616a117973c2", + "size": "341175680" }, { "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-083aad99-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-083aad99-v2.zip", + "checksum": "SHA-256:4c6cae2e34df7e85a149615a6c18169777faf9460f708fc51d93616a117973c2", + "size": "341175680" } ] }, { - "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-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" } ] }, { "name": "esptool_py", - "version": "4.6", + "version": "4.9.dev3", "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" + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC3/esptool-v4.9.dev3-linux-amd64.tar.gz", + "archiveFileName": "esptool-v4.9.dev3-linux-amd64.tar.gz", + "checksum": "SHA-256:4ecaf51836cbf4ea3c19840018bfef3b0b8cd8fc3c95f6e1e043ca5bbeab9bf0", + "size": "64958202" }, { - "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" + "host": "arm-linux-gnueabihf", + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC3/esptool-v4.9.dev3-linux-armv7.tar.gz", + "archiveFileName": "esptool-v4.9.dev3-linux-armv7.tar.gz", + "checksum": "SHA-256:fff818573bce483ee793ac83c8211f6abf764aa3350f198228859f696a0a0b36", + "size": "31530030" }, { "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" - }, - { - "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/arduino-esp32/releases/download/3.1.0-RC3/esptool-v4.9.dev3-linux-aarch64.tar.gz", + "archiveFileName": "esptool-v4.9.dev3-linux-aarch64.tar.gz", + "checksum": "SHA-256:5b274bdff2f62e6a07c3c1dfa51b1128924621f661747eca3dbe0f77972f2f06", + "size": "33663882" }, { "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/arduino-esp32/releases/download/3.1.0-RC3/esptool-v4.9.dev3-macos-amd64.tar.gz", + "archiveFileName": "esptool-v4.9.dev3-macos-amd64.tar.gz", + "checksum": "SHA-256:c733c83b58fcf5f642fbb2fddb8ff24640c2c785126cba0821fb70c4a5ceea7a", + "size": "32767836" }, { - "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": "arm64-apple-darwin", + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC3/esptool-v4.9.dev3-macos-arm64.tar.gz", + "archiveFileName": "esptool-v4.9.dev3-macos-arm64.tar.gz", + "checksum": "SHA-256:83c195a15981e6a5e7a130db2ccfb21e2d8093912e5b003681f9a5abadd71af7", + "size": "30121441" }, { "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/arduino-esp32/releases/download/3.1.0-RC3/esptool-v4.9.dev3-win64.zip", + "archiveFileName": "esptool-v4.9.dev3-win64.zip", + "checksum": "SHA-256:890051a4fdc684ff6f4af18d0bb27d274ca940ee0eef716a9455f8c64b25b215", + "size": "36072564" + }, + { + "host": "x86_64-mingw32", + "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC3/esptool-v4.9.dev3-win64.zip", + "archiveFileName": "esptool-v4.9.dev3-win64.zip", + "checksum": "SHA-256:890051a4fdc684ff6f4af18d0bb27d274ca940ee0eef716a9455f8c64b25b215", + "size": "36072564" } ] }, diff --git a/platform.txt b/platform.txt index d1c3fb3a3dd..44353ab3bf4 100644 --- a/platform.txt +++ b/platform.txt @@ -1,18 +1,15 @@ name=ESP32 Arduino -version=3.0.5 +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 -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 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.windows=esptool.exe tools.esptool_py.network_cmd=python3 "{runtime.platform.path}/tools/espota.py" -r @@ -27,7 +24,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} @@ -47,15 +44,15 @@ compiler.warning_flags.more=-Wall compiler.warning_flags.all=-Wall -Wextra # Additional flags specific to Arduino (not based on IDF flags). -# Update tools/platformio-build.py when changing these flags. +# Update tools/pioarduino-build.py when changing these flags. 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 @@ -69,10 +66,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= @@ -86,6 +83,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={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= @@ -123,7 +121,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 @@ -168,7 +165,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}" @@ -182,7 +178,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 @@ -292,7 +287,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 ## ------------------- @@ -300,7 +294,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) ## ------------------------------------------ @@ -309,7 +302,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/tests/performance/psramspeed/test_psramspeed.py b/tests/performance/psramspeed/test_psramspeed.py index 8d051580799..9e96e158504 100644 --- a/tests/performance/psramspeed/test_psramspeed.py +++ b/tests/performance/psramspeed/test_psramspeed.py @@ -74,7 +74,7 @@ def test_psramspeed(dut, request): sums[(test, size, impl)]["time_sum"] += time avg_results = {} - for (test, size, impl) in sums: + for test, size, impl in sums: rate_avg = round(sums[(test, size, impl)]["rate_sum"] / runs, 2) time_avg = round(sums[(test, size, impl)]["time_sum"] / runs, 2) LOGGER.info( diff --git a/tests/performance/ramspeed/test_ramspeed.py b/tests/performance/ramspeed/test_ramspeed.py index b4c3cee7f9b..dbe1670d329 100644 --- a/tests/performance/ramspeed/test_ramspeed.py +++ b/tests/performance/ramspeed/test_ramspeed.py @@ -74,7 +74,7 @@ def test_ramspeed(dut, request): sums[(test, size, impl)]["time_sum"] += time avg_results = {} - for (test, size, impl) in sums: + for test, size, impl in sums: rate_avg = round(sums[(test, size, impl)]["rate_sum"] / runs, 2) time_avg = round(sums[(test, size, impl)]["time_sum"] / runs, 2) LOGGER.info( diff --git a/tests/requirements.txt b/tests/requirements.txt index a7df8928665..cef0bf17881 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.8 -pytest-embedded-arduino==1.11.8 -pytest-embedded-wokwi==1.11.8 -pytest-embedded-qemu==1.11.8 +pytest-embedded-serial-esp==1.12.0 +pytest-embedded-arduino==1.12.0 +pytest-embedded-wokwi==1.12.0 +pytest-embedded-qemu==1.12.0 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/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); +} diff --git a/tests/validation/uart/diagram.esp32.json b/tests/validation/uart/diagram.esp32.json new file mode 100644 index 00000000000..a31c06d8313 --- /dev/null +++ b/tests/validation/uart/diagram.esp32.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "author": "lucasssvaz", + "editor": "wokwi", + "parts": [ + { + "type": "board-esp32-devkit-c-v4", + "id": "esp", + "attrs": { "cpuFrequency": "40" } + } + ], + "connections": [ + [ + "esp:TX", + "$serialMonitor:RX", + "" + ], + [ + "esp:RX", + "$serialMonitor:TX", + "" + ] + ] +} diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 527d28241d9..27bd95da7f8 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -2,25 +2,20 @@ * * This test is using UART0 (Serial) only for reporting test status and helping with the auto * baudrate detection test. - * UART1 (Serial1) and UART2 (Serial2), where available, are used for testing. + * The other serials are used for testing. */ -#include -#include "HardwareSerial.h" -#include "esp_rom_gpio.h" -#include "Wire.h" - // Default pins: -// | Name | ESP32 | S2 | S3 | C3 | C6 | H2 | -// UART0 RX | SOC_RX0 | 3 | 44 | 44 | 20 | 17 | 23 | -// UART0 TX | SOC_TX0 | 1 | 43 | 43 | 21 | 16 | 24 | -// UART1 RX | RX1 | 26 | 4 | 15 | 18 | 4 | 0 | -// UART1 TX | TX1 | 27 | 5 | 16 | 19 | 5 | 1 | -// UART2 RX | RX2 | 4 | -- | 19 | -- | -- | -- | -// UART2 TX | TX2 | 25 | -- | 20 | -- | -- | -- | +// | Name | ESP32 | S2 | S3 | C3 | C6 | H2 | P4 | +// UART0 RX | SOC_RX0 | 3 | 44 | 44 | 20 | 17 | 23 | 38 | +// UART0 TX | SOC_TX0 | 1 | 43 | 43 | 21 | 16 | 24 | 37 | +// UART1 RX | RX1 | 26 | 4 | 15 | 18 | 4 | 0 | 11 | +// UART1 TX | TX1 | 27 | 5 | 16 | 19 | 5 | 1 | 10 | +// UART2 RX | RX2 | 4 | -- | 19 | -- | -- | -- | -- | +// UART2 TX | TX2 | 25 | -- | 20 | -- | -- | -- | -- | /* - * For 2 UARTS: + * For each UART: * * terminal * | ^ @@ -30,111 +25,95 @@ * report status * | * TX <---> RX - * UART1 - * - * For 3 UARTS: - * - * =====terminal====== - * ^ | ^ ^ - * | v UART0 | | - * | RX TX | - * | | - * ^ report status ^ - * | | - * | TX ---> RX | - * UART2 RX <--- TX UART1 - * + * UARTx */ -#if SOC_UART_NUM == 2 -// Used for the pin swap test -#define NEW_RX1 9 -#define NEW_TX1 10 -#endif +#include +#include +#include "HardwareSerial.h" +#include "esp_rom_gpio.h" +#include "Wire.h" -/* Utility global variables */ +/* Utility defines */ -static String recv_msg = ""; -static int peeked_char = -1; +#define TEST_UART_NUM (uart_test_configs.size()) -/* Utility functions */ +/* Utility classes */ -extern int8_t uart_get_RxPin(uint8_t uart_num); -extern int8_t uart_get_TxPin(uint8_t uart_num); +class UARTTestConfig { +public: + int uart_num; + HardwareSerial &serial; + int peeked_char; + int8_t default_rx_pin; + int8_t default_tx_pin; + String recv_msg; -// This function starts all the available test UARTs -void start_serial(unsigned long baudrate = 115200) { -#if SOC_UART_NUM >= 2 - Serial1.begin(baudrate); - while (!Serial1) { - delay(10); - } -#endif + UARTTestConfig(int num, HardwareSerial &serial_ref, int8_t rx_pin, int8_t tx_pin) + : uart_num(num), serial(serial_ref), peeked_char(-1), default_rx_pin(rx_pin), default_tx_pin(tx_pin), recv_msg("") {} -#if SOC_UART_NUM >= 3 - Serial2.begin(baudrate); - while (!Serial2) { - delay(10); + void begin(unsigned long baudrate) { + serial.begin(baudrate, SERIAL_8N1, default_rx_pin, default_tx_pin); + while (!serial) { + delay(10); + } } -#endif -} - -// This function stops all the available test UARTs -void stop_serial(bool hard_stop = false) { -#if SOC_UART_NUM >= 2 - Serial1.end(/*hard_stop*/); -#endif -#if SOC_UART_NUM >= 3 - Serial2.end(/*hard_stop*/); -#endif -} + void end() { + serial.end(); + } -// 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 - 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()); + void reset_buffers() { + recv_msg = ""; + peeked_char = -1; } -#elif SOC_UART_NUM == 3 - Serial1.print("Hello from Serial1 (UART1) >>> to >>> Serial2 (UART2) " + msg_append); - Serial1.flush(); - delay(100); - if (perform_assert) { - TEST_ASSERT_EQUAL_STRING(("Hello from Serial1 (UART1) >>> to >>> Serial2 (UART2) " + msg_append).c_str(), recv_msg.c_str()); + + void transmit_and_check_msg(const String &msg_append, bool perform_assert = true) { + reset_buffers(); + delay(100); + serial.print("Hello from Serial" + String(uart_num) + " " + msg_append); + serial.flush(); + delay(100); + if (perform_assert) { + TEST_ASSERT_EQUAL_STRING(("Hello from Serial" + String(uart_num) + " " + msg_append).c_str(), recv_msg.c_str()); + log_d("UART%d received message: %s\n", uart_num, recv_msg.c_str()); + } } - Serial2.print("Hello from Serial2 (UART2) >>> to >>> Serial1 (UART1) " + msg_append); - Serial2.flush(); - delay(100); - if (perform_assert) { - TEST_ASSERT_EQUAL_STRING(("Hello from Serial2 (UART2) >>> to >>> Serial1 (UART1) " + msg_append).c_str(), recv_msg.c_str()); + void onReceive() { + char c; + size_t available = serial.available(); + if (peeked_char == -1) { + peeked_char = serial.peek(); + } + while (available--) { + c = (char)serial.read(); + recv_msg += c; + } } -#else - log_d("No UARTs available for transmission"); - TEST_FAIL(); -#endif -} +}; + +/* Utility global variables */ + +[[maybe_unused]] +static const int NEW_RX1 = 9; +[[maybe_unused]] +static const int NEW_TX1 = 10; +std::vector uart_test_configs; + +/* Utility functions */ + +extern "C" int8_t uart_get_RxPin(uint8_t uart_num); +extern "C" int8_t uart_get_TxPin(uint8_t uart_num); /* Tasks */ // This task is used to send a message after a delay to test the auto baudrate detection void task_delayed_msg(void *pvParameters) { - HardwareSerial *selected_serial; - -#if SOC_UART_NUM == 2 - selected_serial = &Serial; -#elif SOC_UART_NUM == 3 - selected_serial = &Serial1; -#endif - + HardwareSerial &selected_serial = uart_test_configs.size() == 1 ? Serial : Serial1; delay(2000); - selected_serial->println("Hello from Serial1 to detect baudrate"); - selected_serial->flush(); + selected_serial.println("Hello to detect baudrate"); + selected_serial.flush(); vTaskDelete(NULL); } @@ -142,67 +121,23 @@ 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 - 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 - log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)"); - - Serial1.onReceive([]() { - onReceive_cb(Serial1); - }); - Serial2.onReceive([]() { - onReceive_cb(Serial2); - }); - uart_internal_loopback(1, RX2); - uart_internal_loopback(2, RX1); -#endif + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + //log_d("Setup internal loop-back from and back to UART%d TX >> UART%d RX", config.uart_num, config.uart_num); + config.begin(115200); + config.serial.onReceive([&config]() { + config.onReceive(); + }); + uart_internal_loopback(config.uart_num, uart_get_RxPin(config.uart_num)); + } } // This function is automatically called by unity after each test is run void tearDown(void) { - stop_serial(); -} - -/* Callback functions */ - -// This is a callback function that will be activated on UART RX events -void onReceive_cb(HardwareSerial &selected_serial) { - int uart_num = -1; - char c; - - (void)uart_num; // Avoid compiler warning when debug level is set to none - - if (&selected_serial == &Serial) { - uart_num = 0; -#if SOC_UART_NUM >= 2 - } else if (&selected_serial == &Serial1) { - uart_num = 1; -#endif -#if SOC_UART_NUM >= 3 - } else if (&selected_serial == &Serial2) { - uart_num = 2; -#endif - } - - recv_msg = ""; - size_t available = selected_serial.available(); - - if (available != 0) { - peeked_char = selected_serial.peek(); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + config.end(); } - - while (available--) { - c = (char)selected_serial.read(); - recv_msg += c; - } - - log_d("UART %d received message: %s\n", uart_num, recv_msg.c_str()); } /* Test functions */ @@ -211,40 +146,33 @@ void onReceive_cb(HardwareSerial &selected_serial) { void basic_transmission_test(void) { log_d("Performing basic transmission test"); - transmit_and_check_msg(""); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + config.transmit_and_check_msg(""); + } Serial.println("Basic transmission test successful"); } // This test checks if the baudrate can be changed and if the message can be transmitted and received correctly after the change void change_baudrate_test(void) { - //Test first using the updateBaudRate method and then using the begin method - log_d("Changing baudrate to 9600"); - - //Baudrate error should be within 2% of the target baudrate - Serial1.updateBaudRate(9600); - TEST_ASSERT_UINT_WITHIN(192, 9600, Serial1.baudRate()); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + log_d("Changing baudrate of UART%d to 9600", config.uart_num); -#if SOC_UART_NUM == 3 - Serial2.updateBaudRate(9600); - TEST_ASSERT_UINT_WITHIN(192, 9600, Serial2.baudRate()); -#endif - - log_d("Sending string using 9600 baudrate"); - transmit_and_check_msg("using 9600 baudrate"); + //Baudrate error should be within 2% of the target baudrate + config.serial.updateBaudRate(9600); + TEST_ASSERT_UINT_WITHIN(192, 9600, config.serial.baudRate()); - log_d("Changing baudrate back to 115200"); - start_serial(115200); + log_d("Sending string on UART%d using 9600 baudrate", config.uart_num); + config.transmit_and_check_msg("using 9600 baudrate"); - //Baudrate error should be within 2% of the target baudrate - TEST_ASSERT_UINT_WITHIN(2304, 115200, Serial1.baudRate()); + config.serial.begin(115200); + TEST_ASSERT_UINT_WITHIN(2304, 115200, config.serial.baudRate()); -#if SOC_UART_NUM == 3 - TEST_ASSERT_UINT_WITHIN(2304, 115200, Serial2.baudRate()); -#endif - - log_d("Sending string using 115200 baudrate"); - transmit_and_check_msg("using 115200 baudrate"); + log_d("Sending string on UART%d using 115200 baudrate", config.uart_num); + config.transmit_and_check_msg("using 115200 baudrate"); + } Serial.println("Change baudrate test successful"); } @@ -261,7 +189,7 @@ void resize_buffers_test(void) { ret = Serial1.setTxBufferSize(256); TEST_ASSERT_EQUAL(0, ret); - stop_serial(); + Serial1.end(); log_d("Trying to resize RX buffer while stopped."); ret = Serial1.setRxBufferSize(256); @@ -277,7 +205,12 @@ void resize_buffers_test(void) { // This test checks if the begin function can be called when the UART is already running void begin_when_running_test(void) { log_d("Trying to set up serial twice"); - start_serial(115200); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + // Calling twice should not crash + config.begin(115200); + config.begin(115200); + } Serial.println("Begin when running test successful"); } @@ -285,9 +218,12 @@ void begin_when_running_test(void) { void end_when_stopped_test(void) { log_d("Trying to end serial twice"); - // Calling end(true) twice should not crash - stop_serial(true); - stop_serial(true); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + // Calling twice should not crash + config.end(); + config.end(); + } Serial.println("End when stopped test successful"); } @@ -311,7 +247,7 @@ void enabled_uart_calls_test(void) { TEST_ASSERT_EQUAL(true, boolean_ret); log_d("Checking if Serial 1 is peekable while running"); - TEST_ASSERT_GREATER_OR_EQUAL(0, peeked_char); + TEST_ASSERT_GREATER_OR_EQUAL(0, uart_test_configs[0]->peeked_char); log_d("Checking if Serial 1 can read bytes while running"); integer_ret = Serial1.readBytes(test_buf, 1); @@ -347,7 +283,10 @@ void disabled_uart_calls_test(void) { int integer_ret; uint8_t test_buf[1]; - stop_serial(); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + config.end(); + } log_d("Checking if Serial 1 can set the RX timeout when stopped"); boolean_ret = Serial1.setRxTimeout(1); @@ -415,44 +354,35 @@ void disabled_uart_calls_test(void) { // This test checks if the pins can be changed and if the message can be transmitted and received correctly after the change void change_pins_test(void) { - //stop_serial(); - log_d("Disabling UART loopback"); -#if SOC_UART_NUM == 2 - esp_rom_gpio_connect_out_signal(SOC_RX0, SIG_GPIO_OUT_IDX, false, false); -#elif SOC_UART_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 - 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 - Serial1.setPins(RX2, TX2); - Serial2.setPins(RX1, TX1); - TEST_ASSERT_EQUAL(RX2, uart_get_RxPin(1)); - TEST_ASSERT_EQUAL(TX2, uart_get_TxPin(1)); - TEST_ASSERT_EQUAL(RX1, uart_get_RxPin(2)); - TEST_ASSERT_EQUAL(TX1, uart_get_TxPin(2)); -#endif - - start_serial(115200); - - log_d("Re-enabling UART loopback"); - -#if SOC_UART_NUM == 2 - uart_internal_loopback(1, NEW_RX1); -#elif SOC_UART_NUM == 3 - uart_internal_loopback(1, RX1); - uart_internal_loopback(2, RX2); -#endif + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + esp_rom_gpio_connect_out_signal(config.default_rx_pin, SIG_GPIO_OUT_IDX, false, false); + } - transmit_and_check_msg("using new pins"); + log_d("Swapping UART pins and testing transmission"); + + if (TEST_UART_NUM == 1) { + UARTTestConfig &config = *uart_test_configs[0]; + config.serial.setPins(NEW_RX1, NEW_TX1); + TEST_ASSERT_EQUAL(NEW_RX1, uart_get_RxPin(config.uart_num)); + TEST_ASSERT_EQUAL(NEW_TX1, uart_get_TxPin(config.uart_num)); + + uart_internal_loopback(config.uart_num, NEW_RX1); + config.transmit_and_check_msg("using new pins"); + } else { + for (int i = 0; i < TEST_UART_NUM; i++) { + UARTTestConfig &config = *uart_test_configs[i]; + UARTTestConfig &next_uart = *uart_test_configs[(i + 1) % TEST_UART_NUM]; + config.serial.setPins(next_uart.default_rx_pin, next_uart.default_tx_pin); + TEST_ASSERT_EQUAL(uart_get_RxPin(config.uart_num), next_uart.default_rx_pin); + TEST_ASSERT_EQUAL(uart_get_TxPin(config.uart_num), next_uart.default_tx_pin); + + uart_internal_loopback(config.uart_num, next_uart.default_rx_pin); + config.transmit_and_check_msg("using new pins"); + } + } Serial.println("Change pins test successful"); } @@ -467,12 +397,15 @@ void auto_baudrate_test(void) { log_d("Stopping test serial. Using Serial2 for ESP32 and Serial1 for ESP32-S2."); -#if SOC_UART_NUM == 2 - selected_serial = &Serial1; - uart_internal_loopback(0, RX1); -#elif SOC_UART_NUM == 3 - selected_serial = &Serial2; + if (TEST_UART_NUM == 1) { + selected_serial = &Serial1; + uart_internal_loopback(0, RX1); + } else { +#ifdef RX2 + selected_serial = &Serial2; + uart_internal_loopback(1, RX2); #endif + } //selected_serial->end(false); @@ -485,10 +418,10 @@ void auto_baudrate_test(void) { selected_serial->begin(0); baudrate = selected_serial->baudRate(); -#if SOC_UART_NUM == 2 - Serial.end(); - Serial.begin(115200); -#endif + if (TEST_UART_NUM == 1) { + Serial.end(); + Serial.begin(115200); + } TEST_ASSERT_UINT_WITHIN(2304, 115200, baudrate); @@ -502,32 +435,23 @@ void periman_test(void) { log_d("Setting up I2C on the same pins as UART"); - Wire.begin(RX1, TX1); - -#if SOC_UART_NUM == 3 - Wire1.begin(RX2, TX2); -#endif - - recv_msg = ""; - - log_d("Trying to send message using UART with I2C enabled"); - transmit_and_check_msg("while used by I2C", false); - TEST_ASSERT_EQUAL_STRING("", recv_msg.c_str()); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + Wire.begin(config.default_rx_pin, config.default_tx_pin); + config.recv_msg = ""; - log_d("Disabling I2C and re-enabling UART"); + log_d("Trying to send message using UART%d with I2C enabled", config.uart_num); + config.transmit_and_check_msg("while used by I2C", false); + TEST_ASSERT_EQUAL_STRING("", config.recv_msg.c_str()); - Serial1.setPins(RX1, TX1); + log_d("Disabling I2C and re-enabling UART%d", config.uart_num); -#if SOC_UART_NUM == 3 - Serial2.setPins(RX2, TX2); - uart_internal_loopback(1, RX2); - uart_internal_loopback(2, RX1); -#elif SOC_UART_NUM == 2 - uart_internal_loopback(1, RX1); -#endif + config.serial.setPins(config.default_rx_pin, config.default_tx_pin); + uart_internal_loopback(config.uart_num, config.default_rx_pin); - log_d("Trying to send message using UART with I2C disabled"); - transmit_and_check_msg("while I2C is disabled"); + log_d("Trying to send message using UART%d with I2C disabled", config.uart_num); + config.transmit_and_check_msg("while I2C is disabled"); + } Serial.println("Peripheral manager test successful"); } @@ -543,8 +467,11 @@ void change_cpu_frequency_test(void) { Serial.updateBaudRate(115200); - log_d("Trying to send message with the new CPU frequency"); - transmit_and_check_msg("with new CPU frequency"); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + log_d("Trying to send message with the new CPU frequency on UART%d", config.uart_num); + config.transmit_and_check_msg("with new CPU frequency"); + } log_d("Changing CPU frequency back to %dMHz", old_freq); Serial.flush(); @@ -552,8 +479,11 @@ void change_cpu_frequency_test(void) { Serial.updateBaudRate(115200); - log_d("Trying to send message with the original CPU frequency"); - transmit_and_check_msg("with the original CPU frequency"); + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + log_d("Trying to send message with the original CPU frequency on UART%d", config.uart_num); + config.transmit_and_check_msg("with the original CPU frequency"); + } Serial.println("Change CPU frequency test successful"); } @@ -565,30 +495,39 @@ void setup() { while (!Serial) { delay(10); } - log_d("SOC_UART_NUM = %d", SOC_UART_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 - 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 - log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)"); - - Serial1.onReceive([]() { - onReceive_cb(Serial1); - }); - Serial2.onReceive([]() { - onReceive_cb(Serial2); - }); - uart_internal_loopback(1, RX2); - uart_internal_loopback(2, RX1); + + uart_test_configs = { +#if SOC_UART_HP_NUM >= 2 && defined(RX1) && defined(TX1) + // inverting RX1<->TX1 because ESP32-P4 has a problem with loopback on RX1 :: GPIO11 <-- UART_TX SGINAL + new UARTTestConfig(1, Serial1, TX1, RX1), +#endif +#if SOC_UART_HP_NUM >= 3 && defined(RX2) && defined(TX2) + new UARTTestConfig(2, Serial2, RX2, TX2), +#endif +#if SOC_UART_HP_NUM >= 4 && defined(RX3) && defined(TX3) + new UARTTestConfig(3, Serial3, RX3, TX3), #endif +#if SOC_UART_HP_NUM >= 5 && defined(RX4) && defined(TX4) + new UARTTestConfig(4, Serial4, RX4, TX4) +#endif + }; + + if (TEST_UART_NUM == 0) { + log_e("This test requires at least one UART besides UART0 configured"); + abort(); + } + + log_d("TEST_UART_NUM = %d", TEST_UART_NUM); + + for (auto *ref : uart_test_configs) { + UARTTestConfig &config = *ref; + config.begin(115200); + log_d("Setup internal loop-back from and back to UART%d TX >> UART%d RX", config.uart_num, config.uart_num); + config.serial.onReceive([&config]() { + config.onReceive(); + }); + uart_internal_loopback(config.uart_num, uart_get_RxPin(config.uart_num)); + } log_d("Setup done. Starting tests"); diff --git a/tests/validation/wifi/ci.json b/tests/validation/wifi/ci.json index 94819d60efc..36e91b221cb 100644 --- a/tests/validation/wifi/ci.json +++ b/tests/validation/wifi/ci.json @@ -21,8 +21,7 @@ "hardware": false, "qemu": false }, - "requires_any": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_WIFI_REMOTE_ENABLED=y" + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" ] } diff --git a/tools/add_lib.sh b/tools/add_lib.sh index 4ec73c4f7f7..9760f8114c6 100755 --- a/tools/add_lib.sh +++ b/tools/add_lib.sh @@ -1,4 +1,5 @@ #!/bin/bash + HELP="This script help to add library when using arduino-esp32 as an ESP-IDF component The script accepts up to three arguments: -n NEW: URL address to new library on GIThub (cannot be combined with -e) @@ -26,119 +27,126 @@ n_param="" # Parse the command-line arguments using getopts while getopts "he:l:n:" opt; do - case $opt in - h) - echo "$HELP" - exit 0 - ;; - e) - #e_param="$OPTARG" - e_param="${OPTARG/#~/$HOME}" - ;; - l) - #l_param="$OPTARG" - l_param="${OPTARG/#~/$HOME}" - ;; - n) - n_param=$OPTARG - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - echo $HELP - exit 1 - ;; - :) - echo "Option -$OPTARG requires an argument." >&2 - echo $HELP - exit 1 - ;; - esac + case $opt in + h) + echo "$HELP" + exit 0 + ;; + e) + #e_param="$OPTARG" + e_param="${OPTARG/#~/$HOME}" + ;; + l) + #l_param="$OPTARG" + l_param="${OPTARG/#~/$HOME}" + ;; + n) + n_param=$OPTARG + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + echo "$HELP" + exit 1 + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + echo "$HELP" + exit 1 + ;; + *) + echo "Invalid option: -$OPTARG" >&2 + echo "$HELP" + exit 1 + ;; + esac done # No parameter check if [[ -z "$e_param" ]] && [[ -z "$l_param" ]] && [[ -z "$n_param" ]]; then - echo "Error: No parameters" >&2 - echo "$HELP" - exit 1 + echo "Error: No parameters" >&2 + echo "$HELP" + exit 1 fi # Only local path check (not permitted) -if [[ -z "$e_param" ]] && [[ ! -z "$l_param" ]] && [[ -z "$n_param" ]]; then - echo "Error: -l parameter must be paired with -e or -n" >&2 - echo "$HELP" - exit 1 +if [[ -z "$e_param" ]] && [[ -n "$l_param" ]] && [[ -z "$n_param" ]]; then + echo "Error: -l parameter must be paired with -e or -n" >&2 + echo "$HELP" + exit 1 fi # Invalid combination check -if [[ ! -z $e_param ]] && [[ ! -z $n_param ]]; then - echo "ERROR: Cannot combine -n with -e" >&2 - echo "$HELP" - exit 1 +if [[ -n $e_param ]] && [[ -n $n_param ]]; then + echo "ERROR: Cannot combine -n with -e" >&2 + echo "$HELP" + exit 1 fi # Check existing lib -if [[ ! -z "$e_param" ]]; then - if [[ ! -d "${e_param/#~/$HOME}" ]]; then # this works! - echo "Error: existing library parameter - path does not exist" >&2 - exit 1 - fi +if [[ -n "$e_param" ]]; then + if [[ ! -d "${e_param/#~/$HOME}" ]]; then # this works! + echo "Error: existing library parameter - path does not exist" >&2 + exit 1 + fi fi LIBRARY="" # Only existing library was supplied -if [[ ! -z $e_param ]] && [[ -z $l_param ]] && [[ -z $n_param ]]; then - LIBRARY=$e_param +if [[ -n $e_param ]] && [[ -z $l_param ]] && [[ -z $n_param ]]; then + LIBRARY=$e_param fi # Install new lib -if [ ! -z $n_param ]; then - INSTALL_TARGET="" - if [ -z $l_param ]; then - # If local path for project is not supplied - use as INSTALL_TARGET Arduino libraries path - INSTALL_TARGET=$ARDUINO_LIBS_PATH/$(basename "$n_param") - else - INSTALL_TARGET=$l_param/components/$(basename "$n_param") - if [ ! -d "$l_param/components" ]; then - echo "Folder components does not exist yet: mkdir -p "$l_param/components"" - mkdir -p "$l_param/components" +if [ -n "$n_param" ]; then + INSTALL_TARGET="" + if [ -z "$l_param" ]; then + # If local path for project is not supplied - use as INSTALL_TARGET Arduino libraries path + INSTALL_TARGET=$ARDUINO_LIBS_PATH/$(basename "$n_param") + else + INSTALL_TARGET=$l_param/components/$(basename "$n_param") + if [ ! -d "$l_param/components" ]; then + echo "Folder components does not exist yet: mkdir -p \"$l_param/components\"" + mkdir -p "$l_param/components" + fi fi - fi - # clone the new lib - echo "Cloning: git clone --recursive $n_param $INSTALL_TARGET" - git clone --recursive $n_param $INSTALL_TARGET - LIBRARY=$INSTALL_TARGET + # clone the new lib + echo "Cloning: git clone --recursive $n_param $INSTALL_TARGET" + git clone --recursive "$n_param" "$INSTALL_TARGET" + LIBRARY=$INSTALL_TARGET fi # Copy existing lib to local project -if [[ ! -z $e_param ]] && [[ ! -z $l_param ]]; then - if [ ! -d "$l_param/components" ]; then - echo "Folder components does not exist yet: mkdir -p "$l_param/components"" - mkdir -p "$l_param/components" - fi - echo "Copy from $e_param to $l_param" - echo "cp -r $e_param $l_param/components/$(basename "$e_param")" - cp -r $e_param $l_param/components/$(basename "$e_param") - LIBRARY=$l_param/components/$(basename "$e_param") +if [[ -n $e_param ]] && [[ -n $l_param ]]; then + if [ ! -d "$l_param/components" ]; then + echo "Folder components does not exist yet: mkdir -p \"$l_param/components\"" + mkdir -p "$l_param/components" + fi + echo "Copy from $e_param to $l_param" + echo "cp -r $e_param $l_param/components/\"$(basename "$e_param")\"" + cp -r "$e_param" "$l_param"/components/"$(basename "$e_param")" + LIBRARY=$l_param/components/"$(basename "$e_param")" fi if [ -z "$LIBRARY" ]; then - echo "ERROR: No library path" >&2 - exit 1 + echo "ERROR: No library path" >&2 + exit 1 fi # 1. get the source list: -FILES=$(find $LIBRARY -name '*.c' -o -name '*.cpp' | xargs -I{} basename {}) +FILES=$(find "$LIBRARY" -print0 -name '*.c' -o -name '*.cpp' | xargs -0 -I{} basename {}) # Fresh start -if [ -f $LIBRARY/CMakeLists.txt ]; then - rm $LIBRARY/CMakeLists.txt - touch $LIBRARY/CMakeLists.txt +if [ -f "$LIBRARY"/CMakeLists.txt ]; then + rm "$LIBRARY"/CMakeLists.txt + touch "$LIBRARY"/CMakeLists.txt fi # Generate CMakeLists.txt -echo "idf_component_register(SRCS $(echo $FILES | sed -e 's/ /" "/g' | sed -e 's/^/"/' -e 's/$/"/')" >> $LIBRARY/CMakeLists.txt -echo " INCLUDE_DIRS \".\"" >> $LIBRARY/CMakeLists.txt -echo " REQUIRES \"arduino-esp32\"" >> $LIBRARY/CMakeLists.txt -echo " )" >> $LIBRARY/CMakeLists.txt +{ + echo "idf_component_register(SRCS $(echo "$FILES" | sed -e 's/ /" "/g' | sed -e 's/^/"/' -e 's/$/"/')" + echo " INCLUDE_DIRS \".\"" + echo " REQUIRES \"arduino-esp32\"" + echo " )" +} >> "$LIBRARY"/CMakeLists.txt diff --git a/tools/gen_esp32part.exe b/tools/gen_esp32part.exe index 51c1959ac74..5bd12c6360d 100644 Binary files a/tools/gen_esp32part.exe and b/tools/gen_esp32part.exe differ diff --git a/tools/gen_esp32part.py b/tools/gen_esp32part.py index 4ba0ee59517..ffa740a36e0 100755 --- a/tools/gen_esp32part.py +++ b/tools/gen_esp32part.py @@ -529,7 +529,7 @@ def to_binary(self): def to_csv(self, simple_formatting=False): def addr_format(a, include_sizes): if not simple_formatting and include_sizes: - for (val, suffix) in [(0x100000, "M"), (0x400, "K")]: + for val, suffix in [(0x100000, "M"), (0x400, "K")]: if a % val == 0: return "%d%s" % (a // val, suffix) return "0x%x" % a diff --git a/tools/get.exe b/tools/get.exe index 671b1507b0b..b56f2b98384 100644 Binary files a/tools/get.exe and b/tools/get.exe differ diff --git a/tools/get.py b/tools/get.py index 1e1e392473c..c791020b7e9 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): @@ -240,11 +243,11 @@ def unpack(filename, destination, force_extract, checksum): # noqa: C901 if filename.endswith("tar.gz"): if not cfile: cfile = tarfile.open(filename, "r:gz") - cfile.extractall(destination) + cfile.extractall(destination, filter="tar") elif filename.endswith("tar.xz"): if not cfile: cfile = tarfile.open(filename, "r:xz") - cfile.extractall(destination) + cfile.extractall(destination, filter="tar") elif filename.endswith("zip"): if not cfile: cfile = zipfile.ZipFile(filename) @@ -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/pioarduino-build.py similarity index 97% rename from tools/platformio-build.py rename to tools/pioarduino-build.py index 1ece3afddff..3335a716888 100644 --- a/tools/platformio-build.py +++ b/tools/pioarduino-build.py @@ -22,7 +22,7 @@ http://arduino.cc/en/Reference/HomePage """ -# Extends: https://github.com/platformio/platform-espressif32/blob/develop/builder/main.py +# Extends: https://github.com/pioarduino/platform-espressif32/blob/develop/builder/main.py from os.path import abspath, basename, isdir, isfile, join from copy import deepcopy @@ -160,7 +160,7 @@ def add_tinyuf2_extra_image(): join( FRAMEWORK_LIBS_DIR, build_mcu, - "platformio-build.py", + "pioarduino-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")), diff --git a/variants/esp32p4/pins_arduino.h b/variants/esp32p4/pins_arduino.h new file mode 100644 index 00000000000..cbb1e871ae5 --- /dev/null +++ b/variants/esp32p4/pins_arduino.h @@ -0,0 +1,85 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// 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; + +// 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; +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; + +/* 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 +#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 + +//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 */