Merge branch 'master' of github.com:adafruit/arduino-esp32

This commit is contained in:
ladyada 2025-05-01 15:42:54 -04:00
commit ee054bc079
315 changed files with 10062 additions and 2099 deletions

View file

@ -1,7 +1,7 @@
[codespell] [codespell]
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/spell-check/.codespellrc # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/spell-check/.codespellrc
# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: # In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
ignore-words-list = ba,licence,ot,dout,als,exten ignore-words-list = ba,licence,ot,dout,als,exten,emac
skip = ./.git,./.licenses,__pycache__,.clang-format,.codespellrc,.editorconfig,.flake8,.prettierignore,.yamllint.yml,.gitignore,boards.txt,platform.txt,programmers.txt skip = ./.git,./.licenses,__pycache__,.clang-format,.codespellrc,.editorconfig,.flake8,.prettierignore,.yamllint.yml,.gitignore,boards.txt,platform.txt,programmers.txt
builtin = clear,informal,en-GB_to_en-US builtin = clear,informal,en-GB_to_en-US
check-filenames = check-filenames =

View file

@ -5,6 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
* Please note that we can only process feature requests reported in English to ensure effective communication and support. Feature requests written in other languages will be closed, with a request to rewrite them in English.
* We welcome any ideas or feature requests! It is helpful if you can explain exactly why the feature would be useful. * We welcome any ideas or feature requests! It is helpful if you can explain exactly why the feature would be useful.
* There are usually some outstanding feature requests in the [existing issues list](https://github.com/espressif/arduino-esp32/issues?q=is%3Aopen+is%3Aissue+label%3A%22Type%3A+Feature+request%22), feel free to add comments to them. * There are usually some outstanding feature requests in the [existing issues list](https://github.com/espressif/arduino-esp32/issues?q=is%3Aopen+is%3Aissue+label%3A%22Type%3A+Feature+request%22), feel free to add comments to them.
* If you would like to contribute, please read the [contributions guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html). * If you would like to contribute, please read the [contributions guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html).

View file

@ -5,6 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
* Please note that we can only process issues reported in English to ensure effective communication and support. Issues written in other languages will be closed, with a request to rewrite them in English.
* 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) * 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) * Take a look on [Troubleshooting guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html)
@ -39,8 +40,13 @@ body:
label: Version label: Version
description: What version of Arduino ESP32 are you running? If possible, consider updating to the latest version. description: What version of Arduino ESP32 are you running? If possible, consider updating to the latest version.
options: options:
- latest master (checkout manually) - latest stable Release (if not listed below)
- latest development Release Candidate (RC-X) - latest development Release Candidate (RC-X)
- latest master (checkout manually)
- v3.2.0
- v3.1.3
- v3.1.2
- v3.1.1
- v3.1.0 - v3.1.0
- v3.0.7 - v3.0.7
- v3.0.6 - v3.0.6

View file

@ -1,8 +1,8 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: Arduino ESP32 Gitter Channel - name: Arduino Core for Espressif Discord Server
url: https://gitter.im/espressif/arduino-esp32 url: https://discord.gg/8xY6e9crwv
about: Community channel for questions and help about: Community Discord server for questions and help
- name: ESP32 Forum - Arduino - name: ESP32 Forum - Arduino
url: https://esp32.com/viewforum.php?f=19 url: https://esp32.com/viewforum.php?f=19
about: Official Forum for questions about: Official Forum for questions

33
.github/scripts/on-push-idf.sh vendored Normal file
View file

@ -0,0 +1,33 @@
#!/bin/bash
set -e
CHECK_REQUIREMENTS="./components/arduino-esp32/.github/scripts/sketch_utils.sh check_requirements"
# Export IDF environment
. ${IDF_PATH}/export.sh
# Find all examples in ./components/arduino-esp32/idf_component_examples
idf_component_examples=$(find ./components/arduino-esp32/idf_component_examples -mindepth 1 -maxdepth 1 -type d)
for example in $idf_component_examples; do
if [ -f "$example"/ci.json ]; then
# If the target is listed as false, skip the sketch. Otherwise, include it.
is_target=$(jq -r --arg target "$IDF_TARGET" '.targets[$target]' "$example"/ci.json)
if [[ "$is_target" == "false" ]]; then
printf "\n\033[93mSkipping %s for target %s\033[0m\n\n" "$example" "$IDF_TARGET"
continue
fi
fi
idf.py -C "$example" set-target "$IDF_TARGET"
has_requirements=$(${CHECK_REQUIREMENTS} "$example" "$example/sdkconfig")
if [ "$has_requirements" -eq 0 ]; then
printf "\n\033[93m%s does not meet the requirements for %s. Skipping...\033[0m\n\n" "$example" "$IDF_TARGET"
continue
fi
printf "\n\033[95mBuilding %s\033[0m\n\n" "$example"
idf.py -C "$example" -DEXTRA_COMPONENT_DIRS="$PWD/components" build
done

View file

@ -35,6 +35,8 @@ PACKAGE_JSON_MERGE="$GITHUB_WORKSPACE/.github/scripts/merge_packages.py"
PACKAGE_JSON_TEMPLATE="$GITHUB_WORKSPACE/package/package_esp32_index.template.json" PACKAGE_JSON_TEMPLATE="$GITHUB_WORKSPACE/package/package_esp32_index.template.json"
PACKAGE_JSON_DEV="package_esp32_dev_index.json" PACKAGE_JSON_DEV="package_esp32_dev_index.json"
PACKAGE_JSON_REL="package_esp32_index.json" PACKAGE_JSON_REL="package_esp32_index.json"
PACKAGE_JSON_DEV_CN="package_esp32_dev_index_cn.json"
PACKAGE_JSON_REL_CN="package_esp32_index_cn.json"
echo "Event: $GITHUB_EVENT_NAME, Repo: $GITHUB_REPOSITORY, Path: $GITHUB_WORKSPACE, Ref: $GITHUB_REF" echo "Event: $GITHUB_EVENT_NAME, Repo: $GITHUB_REPOSITORY, Path: $GITHUB_WORKSPACE, Ref: $GITHUB_REF"
echo "Action: $action, Branch: $RELEASE_BRANCH, ID: $RELEASE_ID" echo "Action: $action, Branch: $RELEASE_BRANCH, ID: $RELEASE_ID"
@ -339,9 +341,13 @@ jq_arg=".packages[0].platforms[0].version = \"$RELEASE_TAG\" | \
# Generate package JSONs # Generate package JSONs
echo "Generating $PACKAGE_JSON_DEV ..." echo "Generating $PACKAGE_JSON_DEV ..."
cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV" cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV"
# On MacOS the sed command won't skip the first match. Use gsed instead.
sed '0,/github\.com\/espressif\//!s|github\.com/espressif/|dl.espressif.cn/github_assets/espressif/|g' "$OUTPUT_DIR/$PACKAGE_JSON_DEV" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN"
if [ "$RELEASE_PRE" == "false" ]; then if [ "$RELEASE_PRE" == "false" ]; then
echo "Generating $PACKAGE_JSON_REL ..." echo "Generating $PACKAGE_JSON_REL ..."
cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_REL" cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_REL"
# On MacOS the sed command won't skip the first match. Use gsed instead.
sed '0,/github\.com\/espressif\//!s|github\.com/espressif/|dl.espressif.cn/github_assets/espressif/|g' "$OUTPUT_DIR/$PACKAGE_JSON_REL" > "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN"
fi fi
# Figure out the last release or pre-release # Figure out the last release or pre-release
@ -373,12 +379,14 @@ echo
if [ -n "$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 ..." echo "Merging with JSON from $prev_any_release ..."
merge_package_json "$prev_any_release/$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV" merge_package_json "$prev_any_release/$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV"
merge_package_json "$prev_any_release/$PACKAGE_JSON_DEV_CN" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN"
fi fi
if [ "$RELEASE_PRE" == "false" ]; then if [ "$RELEASE_PRE" == "false" ]; then
if [ -n "$prev_release" ] && [ "$prev_release" != "null" ]; then if [ -n "$prev_release" ] && [ "$prev_release" != "null" ]; then
echo "Merging with JSON from $prev_release ..." echo "Merging with JSON from $prev_release ..."
merge_package_json "$prev_release/$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL" merge_package_json "$prev_release/$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL"
merge_package_json "$prev_release/$PACKAGE_JSON_REL_CN" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN"
fi fi
fi fi
@ -388,6 +396,8 @@ echo "Installing arduino-cli ..."
export PATH="/home/runner/bin:$PATH" export PATH="/home/runner/bin:$PATH"
source "${SCRIPTS_DIR}/install-arduino-cli.sh" source "${SCRIPTS_DIR}/install-arduino-cli.sh"
# For the Chinese mirror, we can't test the package JSONs as the Chinese mirror might not be updated yet.
echo "Testing $PACKAGE_JSON_DEV install ..." echo "Testing $PACKAGE_JSON_DEV install ..."
echo "Installing esp32 ..." echo "Installing esp32 ..."
@ -445,11 +455,15 @@ fi
echo "Uploading $PACKAGE_JSON_DEV ..." echo "Uploading $PACKAGE_JSON_DEV ..."
echo "Download URL: $(git_safe_upload_asset "$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 "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV")"
echo "Download CN URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")"
echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV_CN")"
echo echo
if [ "$RELEASE_PRE" == "false" ]; then if [ "$RELEASE_PRE" == "false" ]; then
echo "Uploading $PACKAGE_JSON_REL ..." echo "Uploading $PACKAGE_JSON_REL ..."
echo "Download URL: $(git_safe_upload_asset "$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 "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL")"
echo "Download CN URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")"
echo "Pages CN URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL_CN")"
echo echo
fi fi

View file

@ -16,7 +16,7 @@ function check_requirements { # check_requirements <sketchdir> <sdkconfig_path>
local requirements_or local requirements_or
if [ ! -f "$sdkconfig_path" ] || [ ! -f "$sketchdir/ci.json" ]; then if [ ! -f "$sdkconfig_path" ] || [ ! -f "$sketchdir/ci.json" ]; then
echo "ERROR: sdkconfig or ci.json not found" 1>&2 echo "WARNING: sdkconfig or ci.json not found. Assuming requirements are met." 1>&2
# Return 1 on error to force the sketch to be built and fail. This way the # Return 1 on error to force the sketch to be built and fail. This way the
# CI will fail and the user will know that the sketch has a problem. # CI will fail and the user will know that the sketch has a problem.
else else
@ -244,7 +244,7 @@ function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [ext
build_dir="$ARDUINO_BUILD_DIR" build_dir="$ARDUINO_BUILD_DIR"
elif [ "$len" -eq 1 ]; then elif [ "$len" -eq 1 ]; then
# build_dir="$sketchdir/build" # build_dir="$sketchdir/build"
build_dir="$HOME/.arduino/tests/$sketchname/build.tmp" build_dir="$HOME/.arduino/tests/$target/$sketchname/build.tmp"
fi fi
output_file="$HOME/.arduino/cli_compile_output.txt" output_file="$HOME/.arduino/cli_compile_output.txt"
@ -254,7 +254,7 @@ function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [ext
for i in $(seq 0 $((len - 1))); do for i in $(seq 0 $((len - 1))); do
if [ "$len" -ne 1 ]; then if [ "$len" -ne 1 ]; then
# build_dir="$sketchdir/build$i" # build_dir="$sketchdir/build$i"
build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp" build_dir="$HOME/.arduino/tests/$target/$sketchname/build$i.tmp"
fi fi
rm -rf "$build_dir" rm -rf "$build_dir"
mkdir -p "$build_dir" mkdir -p "$build_dir"

View file

@ -11,9 +11,11 @@ function run_test {
local error=0 local error=0
local sdkconfig_path local sdkconfig_path
local extra_args local extra_args
local test_type
sketchdir=$(dirname "$sketch") sketchdir=$(dirname "$sketch")
sketchname=$(basename "$sketchdir") sketchname=$(basename "$sketchdir")
test_type=$(basename "$(dirname "$sketchdir")")
if [ "$options" -eq 0 ] && [ -f "$sketchdir"/ci.json ]; then if [ "$options" -eq 0 ] && [ -f "$sketchdir"/ci.json ]; then
len=$(jq -r --arg target "$target" '.fqbn[$target] | length' "$sketchdir"/ci.json) len=$(jq -r --arg target "$target" '.fqbn[$target] | length' "$sketchdir"/ci.json)
@ -25,9 +27,9 @@ function run_test {
fi fi
if [ "$len" -eq 1 ]; then if [ "$len" -eq 1 ]; then
sdkconfig_path="$HOME/.arduino/tests/$sketchname/build.tmp/sdkconfig" sdkconfig_path="$HOME/.arduino/tests/$target/$sketchname/build.tmp/sdkconfig"
else else
sdkconfig_path="$HOME/.arduino/tests/$sketchname/build0.tmp/sdkconfig" sdkconfig_path="$HOME/.arduino/tests/$target/$sketchname/build0.tmp/sdkconfig"
fi fi
if [ -f "$sketchdir"/ci.json ]; then if [ -f "$sketchdir"/ci.json ]; then
@ -43,22 +45,22 @@ function run_test {
fi fi
if [ ! -f "$sdkconfig_path" ]; then 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 "\033[93mSketch %s build not found in %s\nMight be due to missing target requirements or build failure\033[0m\n" "$(dirname "$sdkconfig_path")" "$sketchname"
printf "\n\n\n" printf "\n\n\n"
return 0 return 0
fi fi
local right_target local compiled_target
right_target=$(grep -E "^CONFIG_IDF_TARGET=\"$target\"$" "$sdkconfig_path") compiled_target=$(grep -E "CONFIG_IDF_TARGET=" "$sdkconfig_path" | cut -d'"' -f2)
if [ -z "$right_target" ]; then if [ "$compiled_target" != "$target" ]; then
printf "\033[91mError: Sketch %s compiled for different target\n\033[0m\n" "$sketchname" printf "\033[91mError: Sketch %s compiled for %s, expected %s\033[0m\n" "$sketchname" "$compiled_target" "$target"
printf "\n\n\n" printf "\n\n\n"
return 1 return 1
fi fi
if [ "$len" -eq 1 ]; then if [ "$len" -eq 1 ]; then
# build_dir="$sketchdir/build" # build_dir="$sketchdir/build"
build_dir="$HOME/.arduino/tests/$sketchname/build.tmp" build_dir="$HOME/.arduino/tests/$target/$sketchname/build.tmp"
report_file="$sketchdir/$target/$sketchname.xml" report_file="$sketchdir/$target/$sketchname.xml"
fi fi
@ -81,7 +83,7 @@ function run_test {
if [ "$len" -ne 1 ]; then if [ "$len" -ne 1 ]; then
# build_dir="$sketchdir/build$i" # build_dir="$sketchdir/build$i"
build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp" build_dir="$HOME/.arduino/tests/$target/$sketchname/build$i.tmp"
report_file="$sketchdir/$target/$sketchname$i.xml" report_file="$sketchdir/$target/$sketchname$i.xml"
fi fi
@ -113,14 +115,14 @@ function run_test {
rm "$sketchdir"/diagram.json 2>/dev/null || true rm "$sketchdir"/diagram.json 2>/dev/null || true
result=0 result=0
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}" printf "\033[95mpytest \"%s/test_%s.py\" --build-dir \"%s\" --junit-xml=\"%s\" -o junit_suite_name=%s_%s_%s_%s%s %s\033[0m\n" "$sketchdir" "$sketchname" "$build_dir" "$report_file" "$test_type" "$platform" "$target" "$sketchname" "$i" "${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=$? bash -c "set +e; pytest \"$sketchdir/test_$sketchname.py\" --build-dir \"$build_dir\" --junit-xml=\"$report_file\" -o junit_suite_name=${test_type}_${platform}_${target}_${sketchname}${i} ${extra_args[*]@Q}; exit \$?" || result=$?
printf "\n" printf "\n"
if [ $result -ne 0 ]; then if [ $result -ne 0 ]; then
result=0 result=0
printf "\033[95mRetrying test: %s -- Config: %s\033[0m\n" "$sketchname" "$i" 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}" printf "\033[95mpytest \"%s/test_%s.py\" --build-dir \"%s\" --junit-xml=\"%s\" -o junit_suite_name=%s_%s_%s_%s%s %s\033[0m\n" "$sketchdir" "$sketchname" "$build_dir" "$report_file" "$test_type" "$platform" "$target" "$sketchname" "$i" "${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=$? bash -c "set +e; pytest \"$sketchdir/test_$sketchname.py\" --build-dir \"$build_dir\" --junit-xml=\"$report_file\" -o junit_suite_name=${test_type}_${platform}_${target}_${sketchname}${i} ${extra_args[*]@Q}; exit \$?" || result=$?
printf "\n" printf "\n"
if [ $result -ne 0 ]; then if [ $result -ne 0 ]; then
printf "\033[91mFailed test: %s -- Config: %s\033[0m\n\n" "$sketchname" "$i" printf "\033[91mFailed test: %s -- Config: %s\033[0m\n\n" "$sketchname" "$i"

View file

@ -15,7 +15,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: ${{ github.event.client_payload.branch }} ref: ${{ github.event.client_payload.branch }}
@ -32,13 +32,13 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: ${{ github.event.client_payload.branch }} ref: ${{ github.event.client_payload.branch }}
- run: npm install - run: npm install
- name: Setup jq - name: Setup jq
uses: dcarbone/install-jq-action@v1.0.1 uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1
- id: set-test-chunks - id: set-test-chunks
name: Set Chunks name: Set Chunks
@ -64,7 +64,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: ${{ github.event.client_payload.branch }} ref: ${{ github.event.client_payload.branch }}
@ -74,7 +74,7 @@ jobs:
FQBN: ${{ toJSON(matrix.chunk) }} FQBN: ${{ toJSON(matrix.chunk) }}
- name: Compile sketch - name: Compile sketch
uses: P-R-O-C-H-Y/compile-sketches@main uses: P-R-O-C-H-Y/compile-sketches@a62f069b92dc8f5053da4ac439ea6d1950cf6379 # main
with: with:
platforms: | platforms: |
${{ env.REPOSITORY }} ${{ env.REPOSITORY }}

View file

@ -22,10 +22,10 @@ jobs:
steps: steps:
# This step makes the contents of the repository available to the workflow # This step makes the contents of the repository available to the workflow
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup jq - name: Setup jq
uses: dcarbone/install-jq-action@v1.0.1 uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1
- name: Get board name - 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}}
@ -47,7 +47,7 @@ jobs:
steps: steps:
# This step makes the contents of the repository available to the workflow # This step makes the contents of the repository available to the workflow
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Check if build.board is uppercase - name: Check if build.board is uppercase
run: | run: |
@ -60,7 +60,7 @@ jobs:
fi fi
- name: Get libs cache - name: Get libs cache
uses: actions/cache@v4 uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with: with:
key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }}
path: | path: |
@ -73,7 +73,7 @@ jobs:
./tools/xtensa-* ./tools/xtensa-*
- name: Compile sketch - name: Compile sketch
uses: P-R-O-C-H-Y/compile-sketches@main uses: P-R-O-C-H-Y/compile-sketches@a62f069b92dc8f5053da4ac439ea6d1950cf6379 # main
with: with:
platforms: | platforms: |
${{ env.REPOSITORY }} ${{ env.REPOSITORY }}

View file

@ -12,13 +12,13 @@ on:
jobs: jobs:
find-changed-tools: find-changed-tools:
name: Check if tools have been changed name: Check if tools have been changed
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
outputs: outputs:
any_changed: ${{ steps.verify-changed-files.outputs.any_changed }} any_changed: ${{ steps.verify-changed-files.outputs.any_changed }}
all_changed_files: ${{ steps.verify-changed-files.outputs.all_changed_files }} all_changed_files: ${{ steps.verify-changed-files.outputs.all_changed_files }}
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
fetch-depth: 2 fetch-depth: 2
ref: ${{ github.event.pull_request.head.ref }} ref: ${{ github.event.pull_request.head.ref }}
@ -30,7 +30,7 @@ jobs:
echo "Make sure you are using a branch inside the repository and not a fork." echo "Make sure you are using a branch inside the repository and not a fork."
- name: Verify Python Tools Changed - name: Verify Python Tools Changed
uses: tj-actions/changed-files@v41 uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1
id: verify-changed-files id: verify-changed-files
with: with:
fetch_depth: "2" fetch_depth: "2"
@ -40,6 +40,7 @@ jobs:
tools/espota.py tools/espota.py
tools/gen_esp32part.py tools/gen_esp32part.py
tools/gen_insights_package.py tools/gen_insights_package.py
- name: List all changed files - name: List all changed files
shell: bash shell: bash
run: | run: |
@ -55,7 +56,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [windows-latest, macos-latest, ubuntu-20.04, ARM] os: [windows-latest, macos-latest, ubuntu-latest, ubuntu-24.04-arm]
include: include:
- os: windows-latest - os: windows-latest
TARGET: win64 TARGET: win64
@ -64,14 +65,12 @@ jobs:
- os: macos-latest - os: macos-latest
TARGET: macos TARGET: macos
SEPARATOR: ":" SEPARATOR: ":"
- os: ubuntu-20.04 - os: ubuntu-latest
TARGET: linux-amd64 TARGET: linux-amd64
SEPARATOR: ":" SEPARATOR: ":"
- os: ARM - os: ubuntu-24.04-arm
CONTAINER: python:3.8-bullseye
TARGET: arm TARGET: arm
SEPARATOR: ":" SEPARATOR: ":"
container: ${{ matrix.CONTAINER }} # use python container on ARM
env: env:
DISTPATH: pytools-${{ matrix.TARGET }} DISTPATH: pytools-${{ matrix.TARGET }}
PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi" PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi"
@ -90,27 +89,30 @@ jobs:
for tool in ${{ env.CHANGED_TOOLS }}; do for tool in ${{ env.CHANGED_TOOLS }}; do
echo "tool $tool was changed" echo "tool $tool was changed"
done done
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
token: ${{ secrets.TOOLS_UPLOAD_PAT }} token: ${{ secrets.TOOLS_UPLOAD_PAT }}
ref: ${{ github.event.pull_request.head.ref }} ref: ${{ github.event.pull_request.head.ref }}
- name: Set up Python 3.8 - name: Set up Python 3.8
# Skip setting python on ARM because of missing compatibility: https://github.com/actions/setup-python/issues/108 uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
if: matrix.os != 'ARM'
uses: actions/setup-python@master
with: with:
python-version: 3.8 python-version: 3.8
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install pyinstaller requests pip install pyinstaller requests
- name: Build with PyInstaller - name: Build with PyInstaller
shell: bash shell: bash
run: | run: |
for tool in ${{ env.CHANGED_TOOLS }}; do for tool in ${{ env.CHANGED_TOOLS }}; do
pyinstaller --distpath ./${{ env.DISTPATH }} -F --icon=.github/pytools/espressif.ico tools/$tool.py pyinstaller --distpath ./${{ env.DISTPATH }} -F --icon=.github/pytools/espressif.ico tools/$tool.py
done done
- name: Sign binaries - name: Sign binaries
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
env: env:
@ -123,12 +125,14 @@ jobs:
{ {
./.github/pytools/Sign-File.ps1 -Path ./${{ env.DISTPATH }}/$node.exe ./.github/pytools/Sign-File.ps1 -Path ./${{ env.DISTPATH }}/$node.exe
} }
- name: Test binaries - name: Test binaries
shell: bash shell: bash
run: | run: |
for tool in ${{ env.CHANGED_TOOLS }}; do for tool in ${{ env.CHANGED_TOOLS }}; do
./${{ env.DISTPATH }}/$tool${{ matrix.EXTEN }} -h ./${{ env.DISTPATH }}/$tool${{ matrix.EXTEN }} -h
done done
- name: Push binary to tools - name: Push binary to tools
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
env: env:
@ -139,8 +143,9 @@ jobs:
cp -f ./${{ env.DISTPATH }}/$tool.exe tools/$tool.exe cp -f ./${{ env.DISTPATH }}/$tool.exe tools/$tool.exe
done done
bash .github/scripts/upload_py_tools.sh "${{ env.CHANGED_TOOLS }}" bash .github/scripts/upload_py_tools.sh "${{ env.CHANGED_TOOLS }}"
- name: Archive artifact - name: Archive artifact
uses: actions/upload-artifact@master uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: ${{ env.DISTPATH }} name: ${{ env.DISTPATH }}
path: ${{ env.DISTPATH }} path: ${{ env.DISTPATH }}

View file

@ -12,12 +12,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out PR head - name: Check out PR head
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: DangerJS pull request linter - name: DangerJS pull request linter
uses: espressif/shared-github-dangerjs@v1 uses: espressif/shared-github-dangerjs@fb17367fd3e8ff7412603b8e946d9b19ffdb2d7f # v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:

View file

@ -21,14 +21,16 @@ jobs:
run: run:
shell: bash shell: bash
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
submodules: true submodules: true
- uses: actions/setup-python@v5
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
with: with:
cache-dependency-path: docs/requirements.txt cache-dependency-path: docs/requirements.txt
cache: "pip" cache: "pip"
python-version: "3.10" python-version: "3.10"
- name: Build - name: Build
run: | run: |
sudo apt update sudo apt update
@ -38,8 +40,9 @@ jobs:
cd ./docs cd ./docs
PATH=/home/runner/.local/bin:$PATH pip3 install -r requirements.txt --prefer-binary 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 PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" build-docs -l en
- name: Archive Docs - name: Archive Docs
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: docs name: docs
path: docs path: docs

View file

@ -26,14 +26,17 @@ jobs:
run: | run: |
echo "Release workflow failed. Exiting..." echo "Release workflow failed. Exiting..."
exit 1 exit 1
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
submodules: true submodules: true
- uses: actions/setup-python@v5
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
with: with:
cache-dependency-path: docs/requirements.txt cache-dependency-path: docs/requirements.txt
cache: "pip" cache: "pip"
python-version: "3.10" python-version: "3.10"
- name: Deploy Documentation - name: Deploy Documentation
env: env:
# Deploy to production server # Deploy to production server

View file

@ -15,7 +15,9 @@ jobs:
name: Build GitHub Pages name: Build GitHub Pages
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Copy Files - name: Copy Files
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -23,16 +23,44 @@
] ]
}, },
{ {
"source-url": "https://github.com/me-no-dev/ESPAsyncWebServer.git", "source-url": "https://github.com/ESP32Async/ESPAsyncWebServer.git",
"required-libs": [ "required-libs": [
{"source-url": "https://github.com/me-no-dev/AsyncTCP.git"} {"source-url": "https://github.com/ESP32Async/AsyncTCP.git"}
], ],
"exclude_targets": [], "exclude_targets": [],
"sketch_path": [ "sketch_path": [
"~/Arduino/libraries/ESPAsyncWebServer/examples/Auth/Auth.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/CORS/CORS.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/CaptivePortal/CaptivePortal.ino", "~/Arduino/libraries/ESPAsyncWebServer/examples/CaptivePortal/CaptivePortal.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino", "~/Arduino/libraries/ESPAsyncWebServer/examples/CatchAllHandler/CatchAllHandler.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/regex_patterns/regex_patterns.ino", "~/Arduino/libraries/ESPAsyncWebServer/examples/ChunkResponse/ChunkResponse.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/simple_server/simple_server.ino" "~/Arduino/libraries/ESPAsyncWebServer/examples/ChunkRetryResponse/ChunkRetryResponse.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/EndBegin/EndBegin.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Filters/Filters.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/FlashResponse/FlashResponse.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/HeaderManipulation/HeaderManipulation.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Headers/Headers.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Json/Json.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Logging/Logging.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/MessagePack/MessagePack.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Middleware/Middleware.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Params/Params.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/PartitionDownloader/PartitionDownloader.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/PerfTests/PerfTests.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/RateLimit/RateLimit.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Redirect/Redirect.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/RequestContinuation/RequestContinuation.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/RequestContinuationComplete/RequestContinuationComplete.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/ResumableDownload/ResumableDownload.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Rewrite/Rewrite.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/ServerSentEvents/ServerSentEvents.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/ServerState/ServerState.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/SkipServerMiddleware/SkipServerMiddleware.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/SlowChunkResponse/SlowChunkResponse.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/StaticFile/StaticFile.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Templates/Templates.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/Upload/Upload.ino",
"~/Arduino/libraries/ESPAsyncWebServer/examples/WebSocket/WebSocket.ino"
] ]
}, },
{ {

View file

@ -62,10 +62,10 @@ jobs:
steps: steps:
# This step makes the contents of the repository available to the workflow # This step makes the contents of the repository available to the workflow
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Compile sketch - name: Compile sketch
uses: P-R-O-C-H-Y/compile-sketches@main uses: P-R-O-C-H-Y/compile-sketches@a62f069b92dc8f5053da4ac439ea6d1950cf6379 # main
with: with:
platforms: | platforms: |
${{ env.REPOSITORY }} ${{ env.REPOSITORY }}
@ -80,7 +80,7 @@ jobs:
- --warnings="all" - --warnings="all"
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }}-${{ matrix.target }} name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }}-${{ matrix.target }}
path: ${{ env.SKETCHES_REPORTS_PATH }} path: ${{ env.SKETCHES_REPORTS_PATH }}
@ -92,7 +92,7 @@ jobs:
steps: steps:
# Check out repository # Check out repository
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
token: ${{ env.GITHUB_TOKEN }} token: ${{ env.GITHUB_TOKEN }}
fetch-depth: "0" fetch-depth: "0"
@ -102,14 +102,14 @@ jobs:
# This step is needed to get the size data produced by the compile jobs # This step is needed to get the size data produced by the compile jobs
- name: Download sketches reports artifact - name: Download sketches reports artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with: with:
pattern: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }}-* pattern: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }}-*
merge-multiple: true merge-multiple: true
path: ${{ env.SKETCHES_REPORTS_PATH }} path: ${{ env.SKETCHES_REPORTS_PATH }}
- name: Report results - name: Report results
uses: P-R-O-C-H-Y/report-size-deltas@main uses: P-R-O-C-H-Y/report-size-deltas@4a79caa6dcc3579024293638b97156106edc588e # main
with: with:
sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }}
destination-file: ${{ env.RESULT_LIBRARY_TEST_FILE }} destination-file: ${{ env.RESULT_LIBRARY_TEST_FILE }}
@ -136,8 +136,9 @@ jobs:
env: env:
PR_NUM: ${{ github.event.number }} PR_NUM: ${{ github.event.number }}
run: echo $PR_NUM > pr_num.txt run: echo $PR_NUM > pr_num.txt
- name: Upload PR number - name: Upload PR number
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: pr_number name: pr_number
path: ./pr_num.txt path: ./pr_num.txt

View file

@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Report success - name: Report success
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
script: | script: |
const owner = '${{ github.repository_owner }}'; const owner = '${{ github.repository_owner }}';
@ -43,7 +43,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Report pending - name: Report pending
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
script: | script: |
const owner = '${{ github.repository_owner }}'; const owner = '${{ github.repository_owner }}';

View file

@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout latest commit - name: Checkout latest commit
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
fetch-depth: 2 fetch-depth: 2
@ -34,7 +34,7 @@ jobs:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
- name: Set up Python 3 - name: Set up Python 3
uses: actions/setup-python@v5 uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
with: with:
cache-dependency-path: tools/pre-commit/requirements.txt cache-dependency-path: tools/pre-commit/requirements.txt
cache: "pip" cache: "pip"
@ -46,7 +46,7 @@ jobs:
echo "PY_HASH=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV echo "PY_HASH=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
- name: Restore pre-commit cache - name: Restore pre-commit cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
id: restore-cache id: restore-cache
with: with:
path: | path: |
@ -58,13 +58,13 @@ jobs:
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
uses: tj-actions/changed-files@v42.0.2 uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1
- name: Run pre-commit hooks in changed files - name: Run pre-commit hooks in changed files
run: pre-commit run --color=always --show-diff-on-failure --files ${{ steps.changed-files.outputs.all_changed_files }} run: pre-commit run --color=always --show-diff-on-failure --files ${{ steps.changed-files.outputs.all_changed_files }}
- name: Save pre-commit cache - name: Save pre-commit cache
uses: actions/cache/save@v4 uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: ${{ always() && steps.restore-cache.outputs.cache-hit != 'true' }} if: ${{ always() && steps.restore-cache.outputs.cache-hit != 'true' }}
continue-on-error: true continue-on-error: true
with: with:
@ -73,7 +73,7 @@ jobs:
key: ${{ steps.restore-cache.outputs.cache-primary-key }} key: ${{ steps.restore-cache.outputs.cache-primary-key }}
- name: Push changes using pre-commit-ci-lite - name: Push changes using pre-commit-ci-lite
uses: pre-commit-ci/lite-action@v1.1.0 uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
# Only push changes in PRs # Only push changes in PRs
if: ${{ always() && github.event_name == 'pull_request' }} if: ${{ always() && github.event_name == 'pull_request' }}
with: with:

View file

@ -44,12 +44,12 @@ jobs:
- name: Read the pr_num file - name: Read the pr_num file
id: pr_num_reader id: pr_num_reader
uses: juliangruber/read-file-action@v1 uses: juliangruber/read-file-action@b549046febe0fe86f8cb4f93c24e284433f9ab58 # v1.1.7
with: with:
path: ./artifacts/workflows/pr_num.txt path: ./artifacts/workflows/pr_num.txt
- name: Report results - name: Report results
uses: P-R-O-C-H-Y/report-size-deltas@libs uses: P-R-O-C-H-Y/report-size-deltas@256d1f13e4195cd7fd436d2f959e6dc4d5e4b406 # libs
with: with:
sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }}
github-token: ${{ env.GITHUB_TOKEN }} github-token: ${{ env.GITHUB_TOKEN }}

View file

@ -14,8 +14,8 @@ jobs:
name: Sizes Comparison Results name: Sizes Comparison Results
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout gh-pages branch
uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: gh-pages ref: gh-pages
@ -34,7 +34,7 @@ jobs:
mv v2.x_cli_compile/*.json artifacts/sizes-report/master/ mv v2.x_cli_compile/*.json artifacts/sizes-report/master/
- name: Report results - name: Report results
uses: P-R-O-C-H-Y/report-size-deltas@sizes_v2 uses: P-R-O-C-H-Y/report-size-deltas@2043188c68f483a7b50527c4eacf609d05bb67a5 # sizes_v2
with: with:
sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }}
github-token: ${{ env.GITHUB_TOKEN }} github-token: ${{ env.GITHUB_TOKEN }}

View file

@ -21,8 +21,8 @@ jobs:
github.event.workflow_run.conclusion == 'success' github.event.workflow_run.conclusion == 'success'
steps: steps:
- name: Checkout code - name: Checkout gh-pages branch
uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: gh-pages ref: gh-pages
@ -60,12 +60,12 @@ jobs:
- name: Read the pr_num file - name: Read the pr_num file
id: pr_num_reader id: pr_num_reader
uses: juliangruber/read-file-action@v1 uses: juliangruber/read-file-action@b549046febe0fe86f8cb4f93c24e284433f9ab58 # v1.1.7
with: with:
path: ./artifacts/sizes-report/pr_num.txt path: ./artifacts/sizes-report/pr_num.txt
- name: Report results - name: Report results
uses: P-R-O-C-H-Y/report-size-deltas@sizes_v2 uses: P-R-O-C-H-Y/report-size-deltas@2043188c68f483a7b50527c4eacf609d05bb67a5 # sizes_v2
with: with:
sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }}
github-token: ${{ env.GITHUB_TOKEN }} github-token: ${{ env.GITHUB_TOKEN }}

View file

@ -31,6 +31,7 @@ on:
- "!libraries/**.properties" - "!libraries/**.properties"
- "!libraries/**.py" - "!libraries/**.py"
- "package/**" - "package/**"
- "idf_component_examples/**"
- "tools/**.py" - "tools/**.py"
- "platform.txt" - "platform.txt"
- "programmers.txt" - "programmers.txt"
@ -45,12 +46,12 @@ on:
- "!.github/scripts/tests_*" - "!.github/scripts/tests_*"
- "!.github/scripts/upload_*" - "!.github/scripts/upload_*"
- "variants/esp32/**/*" - "variants/esp32/**/*"
- "variants/esp32s2/**/*"
- "variants/esp32s3/**/*"
- "variants/esp32c2/**/*"
- "variants/esp32c3/**/*" - "variants/esp32c3/**/*"
- "variants/esp32c6/**/*" - "variants/esp32c6/**/*"
- "variants/esp32h2/**/*" - "variants/esp32h2/**/*"
- "variants/esp32p4/**/*"
- "variants/esp32s2/**/*"
- "variants/esp32s3/**/*"
concurrency: concurrency:
group: build-${{github.event.pull_request.number || github.ref}} group: build-${{github.event.pull_request.number || github.ref}}
@ -65,7 +66,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }} if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- run: bash ./.github/scripts/check-cmakelists.sh - run: bash ./.github/scripts/check-cmakelists.sh
gen-chunks: gen-chunks:
@ -81,13 +82,13 @@ jobs:
chunks: ${{ steps.set-chunks.outputs.chunks }} chunks: ${{ steps.set-chunks.outputs.chunks }}
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
fetch-depth: 2 fetch-depth: 2
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
uses: tj-actions/changed-files@v44 uses: tj-actions/changed-files@2f7c5bfce28377bc069a65ba478de0a74aa0ca32 # v46.0.1
with: with:
files_yaml: | files_yaml: |
core: core:
@ -98,11 +99,12 @@ jobs:
- 'platform.txt' - 'platform.txt'
- 'programmers.txt' - 'programmers.txt'
- "variants/esp32/**/*" - "variants/esp32/**/*"
- "variants/esp32s2/**/*"
- "variants/esp32s3/**/*"
- "variants/esp32c3/**/*" - "variants/esp32c3/**/*"
- "variants/esp32c6/**/*" - "variants/esp32c6/**/*"
- "variants/esp32h2/**/*" - "variants/esp32h2/**/*"
- "variants/esp32p4/**/*"
- "variants/esp32s2/**/*"
- "variants/esp32s3/**/*"
libraries: libraries:
- 'libraries/**/examples/**' - 'libraries/**/examples/**'
- 'libraries/**/src/**' - 'libraries/**/src/**'
@ -122,7 +124,7 @@ jobs:
- 'idf_component.yml' - 'idf_component.yml'
- 'Kconfig.projbuild' - 'Kconfig.projbuild'
- 'CMakeLists.txt' - 'CMakeLists.txt'
- "variants/esp32c2/**/*" - "idf_component_examples/**"
- name: Set chunks - name: Set chunks
id: set-chunks id: set-chunks
@ -142,7 +144,7 @@ jobs:
- name: Upload sketches found - name: Upload sketches found
if: ${{ steps.set-chunks.outputs.build_all == 'false' && steps.set-chunks.outputs.build_libraries == 'true' }} if: ${{ steps.set-chunks.outputs.build_all == 'false' && steps.set-chunks.outputs.build_libraries == 'true' }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: sketches_found name: sketches_found
path: sketches_found.txt path: sketches_found.txt
@ -161,13 +163,13 @@ jobs:
chunk: ${{ fromJson(needs.gen-chunks.outputs.chunks) }} chunk: ${{ fromJson(needs.gen-chunks.outputs.chunks) }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@v5 - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
with: with:
python-version: "3.x" python-version: "3.x"
- name: Get libs cache - name: Get libs cache
uses: actions/cache@v4 uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with: with:
key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }}
path: | path: |
@ -195,7 +197,7 @@ jobs:
- name: Download sketches found - name: Download sketches found
if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }} if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }}
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with: with:
name: sketches_found name: sketches_found
@ -205,7 +207,7 @@ jobs:
#Upload cli compile json as artifact #Upload cli compile json as artifact
- name: Upload cli compile json - name: Upload cli compile json
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: pr_cli_compile_${{ matrix.chunk }} name: pr_cli_compile_${{ matrix.chunk }}
path: cli_compile_${{ matrix.chunk }}.json path: cli_compile_${{ matrix.chunk }}.json
@ -223,8 +225,8 @@ jobs:
os: [windows-latest, macOS-latest] os: [windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@v5 - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
with: with:
python-version: "3.x" python-version: "3.x"
- name: Build Sketches - name: Build Sketches
@ -237,7 +239,7 @@ jobs:
needs.gen-chunks.outputs.build_all == 'true' || needs.gen-chunks.outputs.build_all == 'true' ||
needs.gen-chunks.outputs.build_libraries == 'true' || needs.gen-chunks.outputs.build_libraries == 'true' ||
needs.gen-chunks.outputs.build_idf == 'true' needs.gen-chunks.outputs.build_idf == 'true'
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -245,7 +247,7 @@ jobs:
# See https://hub.docker.com/r/espressif/idf/tags and # 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 # https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html
# for details. # for details.
idf_ver: ["release-v5.3"] idf_ver: ["release-v5.4"]
idf_target: idf_target:
[ [
"esp32", "esp32",
@ -260,19 +262,28 @@ jobs:
container: espressif/idf:${{ matrix.idf_ver }} container: espressif/idf:${{ matrix.idf_ver }}
steps: steps:
- name: Check out arduino-esp32 as a component - name: Check out arduino-esp32 as a component
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
submodules: recursive submodules: recursive
path: components/arduino-esp32 path: components/arduino-esp32
- name: Setup jq
uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1
- name: Build - name: Build
env: env:
IDF_TARGET: ${{ matrix.idf_target }} IDF_TARGET: ${{ matrix.idf_target }}
shell: bash shell: bash
run: | run: |
. ${IDF_PATH}/export.sh chmod a+x ./components/arduino-esp32/.github/scripts/*
idf.py create-project test ./components/arduino-esp32/.github/scripts/on-push-idf.sh
echo CONFIG_FREERTOS_HZ=1000 > test/sdkconfig.defaults
idf.py -C test -DEXTRA_COMPONENT_DIRS=$PWD/components build - name: Upload generated sdkconfig files for debugging
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
with:
name: sdkconfig-${{ matrix.idf_target }}
path: ./components/arduino-esp32/idf_component_examples/**/sdkconfig
# Save artifacts to gh-pages # Save artifacts to gh-pages
save-master-artifacts: save-master-artifacts:
@ -283,7 +294,7 @@ jobs:
steps: steps:
# Check out repository # Check out repository
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
token: ${{secrets.GITHUB_TOKEN}} token: ${{secrets.GITHUB_TOKEN}}
fetch-depth: "0" fetch-depth: "0"
@ -292,7 +303,7 @@ jobs:
run: git checkout remotes/origin/gh-pages run: git checkout remotes/origin/gh-pages
- name: Download sketches reports artifact - name: Download sketches reports artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with: with:
pattern: pr_cli_compile_* pattern: pr_cli_compile_*
merge-multiple: true merge-multiple: true
@ -322,8 +333,9 @@ jobs:
env: env:
PR_NUM: ${{ github.event.number }} PR_NUM: ${{ github.event.number }}
run: echo $PR_NUM > pr_num.txt run: echo $PR_NUM > pr_num.txt
- name: Upload PR number - name: Upload PR number
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: pr_number name: pr_number
path: ./pr_num.txt path: ./pr_num.txt

View file

@ -10,14 +10,22 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: actions/setup-python@v5
- name: Set up Python
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
with: with:
python-version: "3.x" python-version: "3.x"
- run: pip install packaging
- run: pip install pyserial - name: Install packaging
run: pip install packaging
- name: Install pyserial
run: pip install pyserial
- name: Build Release - name: Build Release
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -43,7 +43,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Upload - name: Upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: event_file name: event_file
path: ${{ github.event_path }} path: ${{ github.event_path }}
@ -62,7 +62,7 @@ jobs:
PERFORMANCE_ENABLED: ${{ contains(github.event.pull_request.labels.*.name, 'perf_test') }} PERFORMANCE_ENABLED: ${{ contains(github.event.pull_request.labels.*.name, 'perf_test') }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
sparse-checkout: .github/scripts/tests_matrix.sh sparse-checkout: .github/scripts/tests_matrix.sh
@ -71,7 +71,7 @@ jobs:
run: bash .github/scripts/tests_matrix.sh run: bash .github/scripts/tests_matrix.sh
- name: Upload - name: Upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: matrix_info name: matrix_info
path: info/* path: info/*

View file

@ -22,14 +22,14 @@ jobs:
- name: Check if already built - name: Check if already built
id: cache-build-binaries id: cache-build-binaries
if: github.event.pull_request.number != null if: github.event.pull_request.number != null
uses: actions/cache/restore@v4 uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with: with:
key: tests-${{ env.id }}-bin key: tests-${{ env.id }}-bin
path: | path: |
~/.arduino/tests/**/build*.tmp/*.bin ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.bin
~/.arduino/tests/**/build*.tmp/*.elf ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.elf
~/.arduino/tests/**/build*.tmp/*.json ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.json
~/.arduino/tests/**/build*.tmp/sdkconfig ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/sdkconfig
- name: Evaluate if tests should be built - name: Evaluate if tests should be built
id: check-build id: check-build
@ -46,10 +46,10 @@ jobs:
- name: Checkout user repository - name: Checkout user repository
if: ${{ steps.check-build.outputs.enabled == 'true' }} if: ${{ steps.check-build.outputs.enabled == 'true' }}
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Get libs cache - name: Get libs cache
uses: actions/cache@v4 uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: ${{ steps.check-build.outputs.enabled == 'true' }} if: ${{ steps.check-build.outputs.enabled == 'true' }}
with: with:
key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }}
@ -68,23 +68,23 @@ jobs:
bash .github/scripts/tests_build.sh -c -type ${{ inputs.type }} -t ${{ inputs.chip }} bash .github/scripts/tests_build.sh -c -type ${{ inputs.type }} -t ${{ inputs.chip }}
- name: Upload ${{ inputs.chip }} ${{ inputs.type }} binaries as cache - name: Upload ${{ inputs.chip }} ${{ inputs.type }} binaries as cache
uses: actions/cache/save@v4 uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: steps.check-build.outputs.enabled == 'true' && github.event.pull_request.number != null if: steps.check-build.outputs.enabled == 'true' && github.event.pull_request.number != null
with: with:
key: tests-${{ env.id }}-bin key: tests-${{ env.id }}-bin
path: | path: |
~/.arduino/tests/**/build*.tmp/*.bin ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.bin
~/.arduino/tests/**/build*.tmp/*.elf ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.elf
~/.arduino/tests/**/build*.tmp/*.json ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.json
~/.arduino/tests/**/build*.tmp/sdkconfig ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/sdkconfig
- name: Upload ${{ inputs.chip }} ${{ inputs.type }} binaries as artifacts - name: Upload ${{ inputs.chip }} ${{ inputs.type }} binaries as artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: tests-bin-${{ inputs.chip }}-${{ inputs.type }} name: tests-bin-${{ inputs.chip }}-${{ inputs.type }}
overwrite: true overwrite: true
path: | path: |
~/.arduino/tests/**/build*.tmp/*.bin ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.bin
~/.arduino/tests/**/build*.tmp/*.elf ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.elf
~/.arduino/tests/**/build*.tmp/*.json ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/*.json
~/.arduino/tests/**/build*.tmp/sdkconfig ~/.arduino/tests/${{ inputs.chip }}/**/build*.tmp/sdkconfig

View file

@ -22,17 +22,22 @@ defaults:
jobs: jobs:
hardware-test: hardware-test:
name: Hardware ${{ inputs.chip }} ${{ inputs.type }} tests name: Hardware ${{ inputs.chip }} ${{ inputs.type }} tests
runs-on: [arduino, "${{ inputs.chip }}"] runs-on: ["arduino", "${{ inputs.chip }}"]
env: env:
id: ${{ github.event.pull_request.number || github.ref }}-${{ github.event.pull_request.head.sha || github.sha }}-${{ inputs.chip }}-${{ inputs.type }} id: ${{ github.event.pull_request.number || github.ref }}-${{ github.event.pull_request.head.sha || github.sha }}-${{ inputs.chip }}-${{ inputs.type }}
container: container:
image: python:3.10.1-bullseye image: python:3.10.1-bullseye
options: --privileged options: --privileged --device-cgroup-rule="c 188:* rmw" --device-cgroup-rule="c 166:* rmw"
steps: steps:
- name: Clean workspace
run: |
rm -rf ./*
rm -rf ~/.arduino/tests
- name: Check if already passed - name: Check if already passed
id: cache-results id: cache-results
if: github.event.pull_request.number != null if: github.event.pull_request.number != null
uses: actions/cache/restore@v4 uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with: with:
key: tests-${{ env.id }}-results-hw key: tests-${{ env.id }}-results-hw
path: | path: |
@ -54,13 +59,13 @@ jobs:
- name: Checkout user repository - name: Checkout user repository
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
sparse-checkout: | sparse-checkout: |
* *
# setup-python currently only works on ubuntu images # setup-python currently only works on ubuntu images
# - uses: actions/setup-python@v5 # - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
# if: ${{ steps.check-tests.outputs.enabled == 'true' }} # if: ${{ steps.check-tests.outputs.enabled == 'true' }}
# with: # with:
# cache-dependency-path: tests/requirements.txt # cache-dependency-path: tests/requirements.txt
@ -77,11 +82,16 @@ jobs:
- name: Get binaries - name: Get binaries
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with: with:
name: tests-bin-${{ inputs.chip }}-${{ inputs.type }} name: tests-bin-${{ inputs.chip }}-${{ inputs.type }}
path: | path: |
~/.arduino/tests ~/.arduino/tests/${{ inputs.chip }}
- name: List binaries
if: ${{ steps.check-tests.outputs.enabled == 'true' }}
run: |
ls -laR ~/.arduino/tests
- name: Run Tests - name: Run Tests
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
@ -89,7 +99,7 @@ jobs:
bash .github/scripts/tests_run.sh -c -type ${{ inputs.type }} -t ${{ inputs.chip }} -i 0 -m 1 -e bash .github/scripts/tests_run.sh -c -type ${{ inputs.type }} -t ${{ inputs.chip }} -i 0 -m 1 -e
- name: Upload ${{ inputs.chip }} ${{ inputs.type }} hardware results as cache - name: Upload ${{ inputs.chip }} ${{ inputs.type }} hardware results as cache
uses: actions/cache/save@v4 uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: steps.check-tests.outputs.enabled == 'true' && github.event.pull_request.number != null if: steps.check-tests.outputs.enabled == 'true' && github.event.pull_request.number != null
with: with:
key: tests-${{ env.id }}-results-hw key: tests-${{ env.id }}-results-hw
@ -98,7 +108,7 @@ jobs:
tests/**/result_*.json tests/**/result_*.json
- name: Upload ${{ inputs.chip }} ${{ inputs.type }} hardware results as artifacts - name: Upload ${{ inputs.chip }} ${{ inputs.type }} hardware results as artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always() if: always()
with: with:
name: tests-results-hw-${{ inputs.chip }}-${{ inputs.type }} name: tests-results-hw-${{ inputs.chip }}-${{ inputs.type }}

View file

@ -21,7 +21,7 @@ jobs:
- name: Check if already passed - name: Check if already passed
id: get-cache-results id: get-cache-results
if: github.event.pull_request.number != null if: github.event.pull_request.number != null
uses: actions/cache/restore@v4 uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with: with:
key: tests-${{ env.id }}-results-qemu key: tests-${{ env.id }}-results-qemu
path: | path: |
@ -43,7 +43,7 @@ jobs:
- name: Checkout user repository - name: Checkout user repository
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false persist-credentials: false
@ -60,7 +60,7 @@ jobs:
cd .github cd .github
curl https://codeload.github.com/${{ github.repository }}/tar.gz/master | tar -xz --strip=2 arduino-esp32-master/.github curl https://codeload.github.com/${{ github.repository }}/tar.gz/master | tar -xz --strip=2 arduino-esp32-master/.github
- uses: actions/setup-python@v5 - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
with: with:
cache-dependency-path: tests/requirements.txt cache-dependency-path: tests/requirements.txt
@ -74,14 +74,14 @@ jobs:
pip install -r tests/requirements.txt --extra-index-url https://dl.espressif.com/pypi pip install -r tests/requirements.txt --extra-index-url https://dl.espressif.com/pypi
- name: Install APT dependencies - name: Install APT dependencies
uses: awalsh128/cache-apt-pkgs-action@v1.4.2 uses: awalsh128/cache-apt-pkgs-action@5902b33ae29014e6ca012c5d8025d4346556bd40 # v1.4.3
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
with: with:
packages: libpixman-1-0 libnuma1 libglib2.0-0 libslirp0 libsdl2-2.0-0 packages: libpixman-1-0 libnuma1 libglib2.0-0 libslirp0 libsdl2-2.0-0
version: 1.0 version: 1.0
- name: Get QEMU version - name: Get QEMU version
uses: pozetroninc/github-action-get-latest-release@v0.7.0 uses: pozetroninc/github-action-get-latest-release@2a61c339ea7ef0a336d1daa35ef0cb1418e7676c # v0.8.0
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
id: get-qemu-version id: get-qemu-version
with: with:
@ -92,7 +92,7 @@ jobs:
- name: Cache QEMU - name: Cache QEMU
id: cache-qemu id: cache-qemu
uses: actions/cache@v4 uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
with: with:
path: | path: |
@ -113,18 +113,18 @@ jobs:
- name: Get binaries - name: Get binaries
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with: with:
name: tests-bin-${{ inputs.chip }}-${{ inputs.type }} name: tests-bin-${{ inputs.chip }}-${{ inputs.type }}
path: | path: |
~/.arduino/tests ~/.arduino/tests/${{ inputs.chip }}
- name: Run Tests - name: Run Tests
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
run: QEMU_PATH="${{ env.QEMU_INSTALL_PATH }}" bash .github/scripts/tests_run.sh -c -type ${{inputs.type}} -t ${{inputs.chip}} -i 0 -m 1 -Q run: QEMU_PATH="${{ env.QEMU_INSTALL_PATH }}" bash .github/scripts/tests_run.sh -c -type ${{inputs.type}} -t ${{inputs.chip}} -i 0 -m 1 -Q
- name: Upload ${{ inputs.chip }} ${{ inputs.type }} QEMU results as cache - name: Upload ${{ inputs.chip }} ${{ inputs.type }} QEMU results as cache
uses: actions/cache/save@v4 uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: steps.check-tests.outputs.enabled == 'true' && github.event.pull_request.number != null if: steps.check-tests.outputs.enabled == 'true' && github.event.pull_request.number != null
with: with:
key: tests-${{ env.id }}-results-qemu key: tests-${{ env.id }}-results-qemu
@ -133,7 +133,7 @@ jobs:
tests/**/result_*.json tests/**/result_*.json
- name: Upload ${{ inputs.chip }} ${{ inputs.type }} QEMU results as artifacts - name: Upload ${{ inputs.chip }} ${{ inputs.type }} QEMU results as artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always() if: always()
with: with:
name: tests-results-qemu-${{ inputs.chip }}-${{ inputs.type }} name: tests-results-qemu-${{ inputs.chip }}-${{ inputs.type }}

View file

@ -24,12 +24,12 @@ jobs:
pull-requests: write pull-requests: write
contents: write contents: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: gh-pages ref: gh-pages
- name: Download and Extract Artifacts - name: Download and Extract Artifacts
uses: dawidd6/action-download-artifact@v6 uses: dawidd6/action-download-artifact@07ab29fd4a977ae4d2b275087cf67563dfdf0295 # v9
with: with:
run_id: ${{ github.event.workflow_run.id }} run_id: ${{ github.event.workflow_run.id }}
path: ./artifacts path: ./artifacts
@ -41,6 +41,7 @@ jobs:
original_sha=$(cat ./artifacts/parent-artifacts/sha.txt) original_sha=$(cat ./artifacts/parent-artifacts/sha.txt)
original_ref=$(cat ./artifacts/parent-artifacts/ref.txt) original_ref=$(cat ./artifacts/parent-artifacts/ref.txt)
original_conclusion=$(cat ./artifacts/parent-artifacts/conclusion.txt) original_conclusion=$(cat ./artifacts/parent-artifacts/conclusion.txt)
original_run_id=$(cat ./artifacts/parent-artifacts/run_id.txt)
# Sanitize the values to avoid security issues # Sanitize the values to avoid security issues
@ -59,20 +60,30 @@ jobs:
# Conclusion: Allow alphabetical characters and underscores # Conclusion: Allow alphabetical characters and underscores
original_conclusion=$(echo "$original_conclusion" | tr -cd '[:alpha:]_') original_conclusion=$(echo "$original_conclusion" | tr -cd '[:alpha:]_')
# Run ID: Allow numeric characters
original_run_id=$(echo "$original_run_id" | tr -cd '[:digit:]')
echo "original_event=$original_event" >> $GITHUB_ENV echo "original_event=$original_event" >> $GITHUB_ENV
echo "original_action=$original_action" >> $GITHUB_ENV echo "original_action=$original_action" >> $GITHUB_ENV
echo "original_sha=$original_sha" >> $GITHUB_ENV echo "original_sha=$original_sha" >> $GITHUB_ENV
echo "original_ref=$original_ref" >> $GITHUB_ENV echo "original_ref=$original_ref" >> $GITHUB_ENV
echo "original_conclusion=$original_conclusion" >> $GITHUB_ENV echo "original_conclusion=$original_conclusion" >> $GITHUB_ENV
echo "original_run_id=$original_run_id" >> $GITHUB_ENV
echo "original_event = $original_event" echo "original_event = $original_event"
echo "original_action = $original_action" echo "original_action = $original_action"
echo "original_sha = $original_sha" echo "original_sha = $original_sha"
echo "original_ref = $original_ref" echo "original_ref = $original_ref"
echo "original_conclusion = $original_conclusion" echo "original_conclusion = $original_conclusion"
echo "original_run_id = $original_run_id"
- name: Print links to other runs
run: |
echo "Build, Hardware and QEMU tests: https://github.com/${{ github.repository }}/actions/runs/${{ env.original_run_id }}"
echo "Wokwi tests: https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}"
- name: Publish Unit Test Results - name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v2 uses: EnricoMi/publish-unit-test-result-action@170bf24d20d201b842d7a52403b73ed297e6645b # v2.18.0
with: with:
commit: ${{ env.original_sha }} commit: ${{ env.original_sha }}
event_file: ./artifacts/parent-artifacts/event_file/event.json event_file: ./artifacts/parent-artifacts/event_file/event.json
@ -80,6 +91,17 @@ jobs:
files: ./artifacts/**/*.xml files: ./artifacts/**/*.xml
action_fail: true action_fail: true
compare_to_earlier_commit: false compare_to_earlier_commit: false
json_file: ./unity_results.json
json_suite_details: true
- name: Upload JSON
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: ${{ always() }}
with:
name: unity_results
overwrite: true
path: |
./unity_results.json
- name: Fail if tests failed - name: Fail if tests failed
if: ${{ env.original_conclusion == 'failure' || env.original_conclusion == 'timed_out' || github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'timed_out' }} if: ${{ env.original_conclusion == 'failure' || env.original_conclusion == 'timed_out' || github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'timed_out' }}
@ -87,7 +109,7 @@ jobs:
- name: Clean up caches - name: Clean up caches
if: always() if: always()
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
script: | script: |
const ref = process.env.original_ref; const ref = process.env.original_ref;
@ -117,7 +139,7 @@ jobs:
}); });
- name: Report conclusion - name: Report conclusion
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
if: always() if: always()
with: with:
script: | script: |
@ -138,15 +160,22 @@ jobs:
})).data; })).data;
core.info(`${name} is ${state}`); core.info(`${name} is ${state}`);
- name: Create output folder - name: Generate report
if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled
env:
REPORT_FILE: ./runtime-tests-results/RUNTIME_TESTS_REPORT.md
WOKWI_RUN_ID: ${{ github.event.workflow_run.id }}
BUILD_RUN_ID: ${{ env.original_run_id }}
IS_FAILING: ${{ env.original_conclusion == 'failure' || env.original_conclusion == 'timed_out' || github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'timed_out' || job.status == 'failure' }}
run: | run: |
rm -rf artifacts rm -rf artifacts $REPORT_FILE
mkdir -p runtime-tests-results mv -f ./unity_results.json ./runtime-tests-results/unity_results.json
touch $REPORT_FILE
python3 ./runtime-tests-results/table_generator.py ./runtime-tests-results/unity_results.json >> $REPORT_FILE
- name: Generate badge - name: Generate badge
if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled
uses: jaywcjlove/generated-badges@v1.0.13 uses: jaywcjlove/generated-badges@0e078ae4d4bab3777ea4f137de496ab44688f5ad # v1.0.13
with: with:
label: Runtime Tests label: Runtime Tests
status: ${{ job.status == 'success' && 'passing' || 'failing' }} status: ${{ job.status == 'success' && 'passing' || 'failing' }}
@ -161,6 +190,6 @@ jobs:
git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
if [[ `git status --porcelain` ]]; then if [[ `git status --porcelain` ]]; then
git add --all git add --all
git commit -m "Updated runtime tests badge" git commit -m "Updated runtime tests report"
git push origin HEAD:gh-pages git push origin HEAD:gh-pages
fi fi

View file

@ -27,7 +27,7 @@ jobs:
types: ${{ steps.set-ref.outputs.types }} types: ${{ steps.set-ref.outputs.types }}
steps: steps:
- name: Report pending - name: Report pending
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
script: | script: |
const owner = '${{ github.repository_owner }}'; const owner = '${{ github.repository_owner }}';
@ -47,7 +47,7 @@ jobs:
core.info(`${name} is ${state}`); core.info(`${name} is ${state}`);
- name: Download and extract event file - name: Download and extract event file
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }} run-id: ${{ github.event.workflow_run.id }}
@ -55,7 +55,7 @@ jobs:
path: artifacts/event_file path: artifacts/event_file
- name: Download and extract matrix info - name: Download and extract matrix info
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }} run-id: ${{ github.event.workflow_run.id }}
@ -109,6 +109,10 @@ jobs:
printf "\nAction = " printf "\nAction = "
cat artifacts/action.txt cat artifacts/action.txt
printf "${{ github.event.workflow_run.id }}" >> artifacts/run_id.txt
printf "\nRun ID = "
cat artifacts/run_id.txt
if [ -z "$ref" ] || [ "$ref" == "null" ]; then if [ -z "$ref" ] || [ "$ref" == "null" ]; then
echo "Failed to get PR number or ref" echo "Failed to get PR number or ref"
exit 1 exit 1
@ -126,7 +130,7 @@ jobs:
echo "ref=$ref" >> $GITHUB_OUTPUT echo "ref=$ref" >> $GITHUB_OUTPUT
- name: Download and extract parent hardware results - name: Download and extract parent hardware results
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
continue-on-error: true continue-on-error: true
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
@ -136,7 +140,7 @@ jobs:
path: artifacts/results/hw path: artifacts/results/hw
- name: Download and extract parent QEMU results - name: Download and extract parent QEMU results
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
continue-on-error: true continue-on-error: true
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
@ -146,14 +150,14 @@ jobs:
path: artifacts/results/qemu path: artifacts/results/qemu
- name: Upload parent artifacts - name: Upload parent artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: parent-artifacts name: parent-artifacts
path: artifacts path: artifacts
if-no-files-found: error if-no-files-found: error
- name: Report conclusion - name: Report conclusion
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
if: always() if: always()
with: with:
script: | script: |
@ -193,7 +197,7 @@ jobs:
chip: ${{ fromJson(needs.get-artifacts.outputs.targets) }} chip: ${{ fromJson(needs.get-artifacts.outputs.targets) }}
steps: steps:
- name: Report pending - name: Report pending
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
script: | script: |
const owner = '${{ github.repository_owner }}'; const owner = '${{ github.repository_owner }}';
@ -215,7 +219,7 @@ jobs:
- name: Check if already passed - name: Check if already passed
id: get-cache-results id: get-cache-results
if: needs.get-artifacts.outputs.pr_num if: needs.get-artifacts.outputs.pr_num
uses: actions/cache/restore@v4 uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with: with:
key: tests-${{ env.id }}-results-wokwi key: tests-${{ env.id }}-results-wokwi
path: | path: |
@ -239,11 +243,11 @@ jobs:
# DO NOT CHECKOUT THE USER'S REPOSITORY IN THIS WORKFLOW. IT HAS HIGH SECURITY RISKS. # DO NOT CHECKOUT THE USER'S REPOSITORY IN THIS WORKFLOW. IT HAS HIGH SECURITY RISKS.
- name: Checkout repository - name: Checkout repository
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: ${{ needs.get-artifacts.outputs.base || github.ref }} ref: ${{ needs.get-artifacts.outputs.base || github.ref }}
- uses: actions/setup-python@v5 - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
with: with:
cache-dependency-path: tests/requirements.txt cache-dependency-path: tests/requirements.txt
@ -262,17 +266,17 @@ jobs:
- name: Wokwi CI Server - name: Wokwi CI Server
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: wokwi/wokwi-ci-server-action@v1 uses: wokwi/wokwi-ci-server-action@a6fabb5a49e080158c7a1d121ea5b789536a82c3 # v1
- name: Get binaries - name: Get binaries
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }} run-id: ${{ github.event.workflow_run.id }}
name: tests-bin-${{ matrix.chip }}-${{ matrix.type }} name: tests-bin-${{ matrix.chip }}-${{ matrix.type }}
path: | path: |
~/.arduino/tests ~/.arduino/tests/${{ matrix.chip }}
- name: Run Tests - name: Run Tests
if: ${{ steps.check-tests.outputs.enabled == 'true' }} if: ${{ steps.check-tests.outputs.enabled == 'true' }}
@ -282,7 +286,7 @@ jobs:
bash .github/scripts/tests_run.sh -c -type ${{ matrix.type }} -t ${{ matrix.chip }} -i 0 -m 1 -W ${{ env.WOKWI_TIMEOUT }} bash .github/scripts/tests_run.sh -c -type ${{ matrix.type }} -t ${{ matrix.chip }} -i 0 -m 1 -W ${{ env.WOKWI_TIMEOUT }}
- name: Upload ${{ matrix.chip }} ${{ matrix.type }} Wokwi results as cache - name: Upload ${{ matrix.chip }} ${{ matrix.type }} Wokwi results as cache
uses: actions/cache/save@v4 uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: steps.check-tests.outputs.enabled == 'true' && needs.get-artifacts.outputs.pr_num if: steps.check-tests.outputs.enabled == 'true' && needs.get-artifacts.outputs.pr_num
with: with:
key: tests-${{ env.id }}-results-wokwi key: tests-${{ env.id }}-results-wokwi
@ -291,7 +295,7 @@ jobs:
tests/**/result_*.json tests/**/result_*.json
- name: Upload ${{ matrix.chip }} ${{ matrix.type }} Wokwi results as artifacts - name: Upload ${{ matrix.chip }} ${{ matrix.type }} Wokwi results as artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always() if: always()
with: with:
name: tests-results-wokwi-${{ matrix.chip }}-${{ matrix.type }} name: tests-results-wokwi-${{ matrix.chip }}-${{ matrix.type }}
@ -301,7 +305,7 @@ jobs:
tests/**/result_*.json tests/**/result_*.json
- name: Report conclusion - name: Report conclusion
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
if: always() if: always()
with: with:
script: | script: |

View file

@ -45,13 +45,13 @@ jobs:
echo "Tag: $tag" echo "Tag: $tag"
echo "RELEASE_TAG=$tag" >> $GITHUB_ENV echo "RELEASE_TAG=$tag" >> $GITHUB_ENV
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: ${{ inputs.git_ref || env.RELEASE_TAG }} ref: ${{ inputs.git_ref || env.RELEASE_TAG }}
submodules: "recursive" submodules: "recursive"
- name: Upload components to the component registry - name: Upload components to the component registry
uses: espressif/upload-components-ci-action@v1 uses: espressif/upload-components-ci-action@b78a19fa5424714997596d3ecffa634aef8ae20b # v1.0.5
with: with:
name: arduino-esp32 name: arduino-esp32
version: ${{ env.RELEASE_TAG }} version: ${{ env.RELEASE_TAG }}

View file

@ -12,7 +12,7 @@ default_language_version:
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: "v5.0.0" rev: "cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b" # v5.0.0
hooks: hooks:
# Generic checks # Generic checks
- id: check-case-conflict - id: check-case-conflict
@ -39,15 +39,8 @@ repos:
^package\/.*$ ^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 - repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v18.1.3" rev: "f6446549e5e97ec9665b9b03e75b87b445857f9a" # v18.1.3
hooks: hooks:
# C/C++ formatting # C/C++ formatting
- id: clang-format - id: clang-format
@ -55,7 +48,7 @@ repos:
exclude: ^.*\/build_opt\.h$ exclude: ^.*\/build_opt\.h$
- repo: https://github.com/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror
rev: "24.10.0" rev: "a4920527036bb9a3f3e6055d595849d67d0da066" # 25.1.0
hooks: hooks:
# Python formatting # Python formatting
- id: black - id: black
@ -63,7 +56,7 @@ repos:
args: [--line-length=120] #From the arduino code style. Add as argument rather than creating a new config file. 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 - repo: https://github.com/PyCQA/flake8
rev: "7.1.1" rev: "16f5f28a384f0781bebb37a08aa45e65b9526c50" # 7.2.0
hooks: hooks:
# Python linting # Python linting
- id: flake8 - id: flake8
@ -74,21 +67,28 @@ repos:
- flake8-simplify - flake8-simplify
- repo: https://github.com/pre-commit/mirrors-prettier - repo: https://github.com/pre-commit/mirrors-prettier
rev: "v3.1.0" rev: "ffb6a759a979008c0e6dff86e39f4745a2d9eac4" # v3.1.0
hooks: hooks:
# YAML formatting # YAML formatting
- id: prettier - id: prettier
types_or: [yaml] types_or: [yaml]
- repo: https://github.com/codespell-project/codespell
rev: "63c8f8312b7559622c0d82815639671ae42132ac" # v2.4.1
hooks:
# Spell checking
- id: codespell
exclude: ^.*\.(svd|SVD)$
- repo: https://github.com/shellcheck-py/shellcheck-py - repo: https://github.com/shellcheck-py/shellcheck-py
rev: "v0.10.0.1" rev: "a23f6b85d0fdd5bb9d564e2579e678033debbdff" # v0.10.0.1
hooks: hooks:
# Bash linting # Bash linting
- id: shellcheck - id: shellcheck
types: [shell] types: [shell]
- repo: https://github.com/openstack/bashate - repo: https://github.com/openstack/bashate
rev: "2.1.1" rev: "fbd7c2534c2701351c603ff700ddf08202430a31" # 2.1.1
hooks: hooks:
# Bash formatting # Bash formatting
- id: bashate - id: bashate
@ -96,15 +96,15 @@ repos:
args: ["-i", "E006"] # Ignore E006: Line too long args: ["-i", "E006"] # Ignore E006: Line too long
- repo: https://github.com/errata-ai/vale - repo: https://github.com/errata-ai/vale
rev: "v3.9.1" rev: "dc4c47923788a413fb5677de6e3370d514aecb78" # v3.11.2
hooks: hooks:
# Sync vale styles and lint markdown and reStructuredText # Sync vale styles and lint markdown and reStructuredText
- id: vale - id: vale
name: vale-sync name: vale-sync
language_version: "1.21.6" language_version: "1.23.2"
pass_filenames: false pass_filenames: false
args: [sync] args: [sync]
types_or: [markdown, rst] types_or: [markdown, rst]
- id: vale - id: vale
language_version: "1.21.6" language_version: "1.23.2"
types_or: [markdown, rst] types_or: [markdown, rst]

View file

@ -6,7 +6,7 @@
# idf.py build # idf.py build
set(min_supported_idf_version "5.3.0") set(min_supported_idf_version "5.3.0")
set(max_supported_idf_version "5.3.99") set(max_supported_idf_version "5.4.99")
set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}") set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}")
if ("${idf_version}" AND NOT "$ENV{ARDUINO_SKIP_IDF_VERSION_CHECK}") if ("${idf_version}" AND NOT "$ENV{ARDUINO_SKIP_IDF_VERSION_CHECK}")
@ -33,6 +33,7 @@ set(CORE_SRCS
cores/esp32/esp32-hal-dac.c cores/esp32/esp32-hal-dac.c
cores/esp32/esp32-hal-gpio.c cores/esp32/esp32-hal-gpio.c
cores/esp32/esp32-hal-i2c.c cores/esp32/esp32-hal-i2c.c
cores/esp32/esp32-hal-i2c-ng.c
cores/esp32/esp32-hal-i2c-slave.c cores/esp32/esp32-hal-i2c-slave.c
cores/esp32/esp32-hal-ledc.c cores/esp32/esp32-hal-ledc.c
cores/esp32/esp32-hal-matrix.c cores/esp32/esp32-hal-matrix.c
@ -290,6 +291,16 @@ set(ARDUINO_LIBRARY_Zigbee_SRCS
libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp
libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp
libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp
libraries/Zigbee/src/ep/ZigbeeContactSwitch.cpp
libraries/Zigbee/src/ep/ZigbeeDoorWindowHandle.cpp
libraries/Zigbee/src/ep/ZigbeeWindowCovering.cpp
libraries/Zigbee/src/ep/ZigbeeVibrationSensor.cpp
libraries/Zigbee/src/ep/ZigbeeAnalog.cpp
libraries/Zigbee/src/ep/ZigbeeRangeExtender.cpp
libraries/Zigbee/src/ep/ZigbeeGateway.cpp
libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp
libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp
libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp
) )
set(ARDUINO_LIBRARY_BLE_SRCS set(ARDUINO_LIBRARY_BLE_SRCS

View file

@ -1,11 +1,13 @@
# Arduino core for the ESP32, ESP32-P4, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6 and ESP32-H2 # Arduino core for the ESP32, ESP32-C3, ESP32-C6, ESP32-H2, ESP32-P4, ESP32-S2 and ESP32-S3.
[![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) [![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) [![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) [![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) [![Runtime Tests](https://github.com/espressif/arduino-esp32/blob/gh-pages/runtime-tests-results/badge.svg)](https://github.com/espressif/arduino-esp32/blob/gh-pages/runtime-tests-results/RUNTIME_TESTS_REPORT.md)
### 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) ### Need help or have a question? Join the chat at [Discord](https://discord.gg/8xY6e9crwv) or [open a new Discussion](https://github.com/espressif/arduino-esp32/discussions)
[![Discord invite](https://img.shields.io/discord/1327272229427216425?logo=discord&logoColor=white&logoSize=auto&label=Discord)](https://discord.gg/8xY6e9crwv)
## Contents ## Contents
@ -65,16 +67,17 @@ Here are the ESP32 series supported by the Arduino-ESP32 project:
| **SoC** | **Stable** | **Development** | **Datasheet** | | **SoC** | **Stable** | **Development** | **Datasheet** |
|----------|:----------:|:---------------:|:-------------------------------------------------------------------------------------------------:| |----------|:----------:|:---------------:|:-------------------------------------------------------------------------------------------------:|
| ESP32 | Yes | Yes | [ESP32](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) | | ESP32 | Yes | Yes | [ESP32](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) |
| ESP32-S2 | Yes | Yes | [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) |
| ESP32-C3 | Yes | Yes | [ESP32-C3](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) | | ESP32-C3 | Yes | Yes | [ESP32-C3](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) |
| 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-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-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) | | ESP32-P4 | Yes | Yes | [ESP32-P4](https://www.espressif.com/sites/default/files/documentation/esp32-p4_datasheet_en.pdf) |
| ESP32-S2 | Yes | Yes | [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) |
| ESP32-S3 | Yes | Yes | [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) |
> [!NOTE] > [!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 > ESP32-C2 is also supported by Arduino-ESP32 but requires using Arduino as an ESP-IDF component or rebuilding the static libraries.
> build system. For more information, see the [Lib Builder documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/lib_builder.html). > For more information, see the [Arduino as an ESP-IDF component documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html) or the
> [Lib Builder documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/lib_builder.html), respectively.
For more details visit the [supported chips](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html#supported-soc-s) documentation page. For more details visit the [supported chips](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html#supported-soc-s) documentation page.

1184
boards.txt

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,6 @@
#include "extra_attr.h" #include "extra_attr.h"
#include "pins_arduino.h" #include "pins_arduino.h"
#include "io_pin_remap.h"
#include "esp32-hal.h" #include "esp32-hal.h"
#define PI 3.1415926535897932384626433832795 #define PI 3.1415926535897932384626433832795
@ -251,4 +250,8 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin); void noTone(uint8_t _pin);
#endif /* __cplusplus */ #endif /* __cplusplus */
// must be applied last as it overrides some of the above
#include "io_pin_remap.h"
#endif /* _ESP32_CORE_ARDUINO_H_ */ #endif /* _ESP32_CORE_ARDUINO_H_ */

View file

@ -603,6 +603,7 @@ void HWCDC::setDebugOutput(bool en) {
} else { } else {
ets_install_putc2(NULL); ets_install_putc2(NULL);
} }
ets_install_putc1(NULL); // closes UART log output
} }
#if ARDUINO_USB_MODE && ARDUINO_USB_CDC_ON_BOOT // Hardware JTAG CDC selected #if ARDUINO_USB_MODE && ARDUINO_USB_CDC_ON_BOOT // Hardware JTAG CDC selected

View file

@ -11,52 +11,52 @@
#include "driver/uart.h" #include "driver/uart.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE #if (SOC_UART_LP_NUM >= 1)
#define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048 #define UART_HW_FIFO_LEN(uart_num) ((uart_num < SOC_UART_HP_NUM) ? SOC_UART_FIFO_LEN : SOC_LP_UART_FIFO_LEN)
#endif #else
#define UART_HW_FIFO_LEN(uart_num) SOC_UART_FIFO_LEN
#ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY
#define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#endif
#ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
#define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1
#endif #endif
void serialEvent(void) __attribute__((weak)); void serialEvent(void) __attribute__((weak));
#if SOC_UART_HP_NUM > 1 #if SOC_UART_NUM > 1
void serialEvent1(void) __attribute__((weak)); void serialEvent1(void) __attribute__((weak));
#endif /* SOC_UART_HP_NUM > 1 */ #endif /* SOC_UART_NUM > 1 */
#if SOC_UART_HP_NUM > 2 #if SOC_UART_NUM > 2
void serialEvent2(void) __attribute__((weak)); void serialEvent2(void) __attribute__((weak));
#endif /* SOC_UART_HP_NUM > 2 */ #endif /* SOC_UART_NUM > 2 */
#if SOC_UART_HP_NUM > 3 #if SOC_UART_NUM > 3
void serialEvent3(void) __attribute__((weak)); void serialEvent3(void) __attribute__((weak));
#endif /* SOC_UART_HP_NUM > 3 */ #endif /* SOC_UART_NUM > 3 */
#if SOC_UART_HP_NUM > 4 #if SOC_UART_NUM > 4
void serialEvent4(void) __attribute__((weak)); void serialEvent4(void) __attribute__((weak));
#endif /* SOC_UART_HP_NUM > 4 */ #endif /* SOC_UART_NUM > 4 */
#if SOC_UART_NUM > 5
void serialEvent5(void) __attribute__((weak));
#endif /* SOC_UART_NUM > 5 */
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
// There is always Seria0 for UART0 // There is always Seria0 for UART0
HardwareSerial Serial0(0); HardwareSerial Serial0(0);
#if SOC_UART_HP_NUM > 1 #if SOC_UART_NUM > 1
HardwareSerial Serial1(1); HardwareSerial Serial1(1);
#endif #endif
#if SOC_UART_HP_NUM > 2 #if SOC_UART_NUM > 2
HardwareSerial Serial2(2); HardwareSerial Serial2(2);
#endif #endif
#if SOC_UART_HP_NUM > 3 #if SOC_UART_NUM > 3
HardwareSerial Serial3(3); HardwareSerial Serial3(3);
#endif #endif
#if SOC_UART_HP_NUM > 4 #if SOC_UART_NUM > 4
HardwareSerial Serial4(4); HardwareSerial Serial4(4);
#endif #endif
#if (SOC_UART_NUM > 5)
HardwareSerial Serial5(5);
#endif
#if HWCDC_SERIAL_IS_DEFINED == 1 // Hardware JTAG CDC Event #if HWCDC_SERIAL_IS_DEFINED == 1 // Hardware JTAG CDC Event
extern void HWCDCSerialEvent(void) __attribute__((weak)); extern void HWCDCSerialEvent(void) __attribute__((weak));
#endif #endif
@ -81,26 +81,31 @@ void serialEventRun(void) {
if (serialEvent && Serial0.available()) { if (serialEvent && Serial0.available()) {
serialEvent(); serialEvent();
} }
#if SOC_UART_HP_NUM > 1 #if SOC_UART_NUM > 1
if (serialEvent1 && Serial1.available()) { if (serialEvent1 && Serial1.available()) {
serialEvent1(); serialEvent1();
} }
#endif #endif
#if SOC_UART_HP_NUM > 2 #if SOC_UART_NUM > 2
if (serialEvent2 && Serial2.available()) { if (serialEvent2 && Serial2.available()) {
serialEvent2(); serialEvent2();
} }
#endif #endif
#if SOC_UART_HP_NUM > 3 #if SOC_UART_NUM > 3
if (serialEvent3 && Serial3.available()) { if (serialEvent3 && Serial3.available()) {
serialEvent3(); serialEvent3();
} }
#endif #endif
#if SOC_UART_HP_NUM > 4 #if SOC_UART_NUM > 4
if (serialEvent4 && Serial4.available()) { if (serialEvent4 && Serial4.available()) {
serialEvent4(); serialEvent4();
} }
#endif #endif
#if SOC_UART_NUM > 5
if (serialEvent5 && Serial5.available()) {
serialEvent5();
}
#endif
} }
#endif #endif
@ -185,7 +190,8 @@ void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) {
// in case that onReceive() shall work only with RX Timeout, FIFO shall be high // in case that onReceive() shall work only with RX Timeout, FIFO shall be high
// this is a work around for an IDF issue with events and low FIFO Full value (< 3) // this is a work around for an IDF issue with events and low FIFO Full value (< 3)
if (_onReceiveTimeout) { // Not valid for the LP UART
if (_onReceiveTimeout && _uart_nr < SOC_UART_HP_NUM) {
uartSetRxFIFOFull(_uart, 120); uartSetRxFIFOFull(_uart, 120);
log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes."); log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes.");
} }
@ -207,12 +213,13 @@ bool HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) {
HSERIAL_MUTEX_LOCK(); HSERIAL_MUTEX_LOCK();
// in case that onReceive() shall work only with RX Timeout, FIFO shall be high // in case that onReceive() shall work only with RX Timeout, FIFO shall be high
// this is a work around for an IDF issue with events and low FIFO Full value (< 3) // this is a work around for an IDF issue with events and low FIFO Full value (< 3)
if (_onReceiveCB != NULL && _onReceiveTimeout) { // Not valid for the LP UART
if (_onReceiveCB != NULL && _onReceiveTimeout && _uart_nr < SOC_UART_HP_NUM) {
fifoBytes = 120; fifoBytes = 120;
log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes."); log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes.");
} }
bool retCode = uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout bool retCode = uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout
if (fifoBytes > 0 && fifoBytes < SOC_UART_FIFO_LEN - 1) { if (fifoBytes > 0 && fifoBytes < UART_HW_FIFO_LEN(_uart_nr) - 1) {
_rxFIFOFull = fifoBytes; _rxFIFOFull = fifoBytes;
} }
HSERIAL_MUTEX_UNLOCK(); HSERIAL_MUTEX_UNLOCK();
@ -298,8 +305,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) { 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_HP_NUM) { if (_uart_nr >= SOC_UART_NUM) {
log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_HP_NUM - 1); log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_NUM - 1);
return; return;
} }
@ -333,7 +340,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
txPin = _txPin < 0 ? (int8_t)SOC_TX0 : _txPin; txPin = _txPin < 0 ? (int8_t)SOC_TX0 : _txPin;
} }
break; break;
#if SOC_UART_HP_NUM > 1 // may save some flash bytes... #if SOC_UART_HP_NUM > 1
case UART_NUM_1: case UART_NUM_1:
if (rxPin < 0 && txPin < 0) { if (rxPin < 0 && txPin < 0) {
// do not change RX1/TX1 if it has already been set before // do not change RX1/TX1 if it has already been set before
@ -341,8 +348,8 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
txPin = _txPin < 0 ? (int8_t)TX1 : _txPin; txPin = _txPin < 0 ? (int8_t)TX1 : _txPin;
} }
break; break;
#endif #endif // UART_NUM_1
#if SOC_UART_HP_NUM > 2 // may save some flash bytes... #if SOC_UART_HP_NUM > 2
case UART_NUM_2: case UART_NUM_2:
if (rxPin < 0 && txPin < 0) { if (rxPin < 0 && txPin < 0) {
// do not change RX2/TX2 if it has already been set before // do not change RX2/TX2 if it has already been set before
@ -354,11 +361,11 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
#endif #endif
} }
break; break;
#endif #endif // UART_NUM_2
#if SOC_UART_HP_NUM > 3 // may save some flash bytes... #if SOC_UART_HP_NUM > 3
case UART_NUM_3: case UART_NUM_3:
if (rxPin < 0 && txPin < 0) { if (rxPin < 0 && txPin < 0) {
// do not change RX2/TX2 if it has already been set before // do not change RX3/TX3 if it has already been set before
#ifdef RX3 #ifdef RX3
rxPin = _rxPin < 0 ? (int8_t)RX3 : _rxPin; rxPin = _rxPin < 0 ? (int8_t)RX3 : _rxPin;
#endif #endif
@ -367,11 +374,11 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
#endif #endif
} }
break; break;
#endif #endif // UART_NUM_3
#if SOC_UART_HP_NUM > 4 // may save some flash bytes... #if SOC_UART_HP_NUM > 4
case UART_NUM_4: case UART_NUM_4:
if (rxPin < 0 && txPin < 0) { if (rxPin < 0 && txPin < 0) {
// do not change RX2/TX2 if it has already been set before // do not change RX4/TX4 if it has already been set before
#ifdef RX4 #ifdef RX4
rxPin = _rxPin < 0 ? (int8_t)RX4 : _rxPin; rxPin = _rxPin < 0 ? (int8_t)RX4 : _rxPin;
#endif #endif
@ -380,7 +387,20 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
#endif #endif
} }
break; break;
#endif // UART_NUM_4
#if (SOC_UART_LP_NUM >= 1)
case LP_UART_NUM_0:
if (rxPin < 0 && txPin < 0) {
// do not change RX0_LP/TX0_LP if it has already been set before
#ifdef LP_RX0
rxPin = _rxPin < 0 ? (int8_t)LP_RX0 : _rxPin;
#endif #endif
#ifdef LP_TX0
txPin = _txPin < 0 ? (int8_t)LP_TX0 : _txPin;
#endif
}
break;
#endif // LP_UART_NUM_0
} }
} }
@ -445,7 +465,8 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
if (!_rxFIFOFull) { // it has not being changed before calling begin() if (!_rxFIFOFull) { // it has not being changed before calling begin()
// set a default FIFO Full value for the IDF driver // set a default FIFO Full value for the IDF driver
uint8_t fifoFull = 1; uint8_t fifoFull = 1;
if (baud > 57600 || (_onReceiveCB != NULL && _onReceiveTimeout)) { // if baud rate is higher than 57600 or onReceive() is set, it will set FIFO Full to 120 bytes, except for LP UART
if (_uart_nr < SOC_UART_HP_NUM && (baud > 57600 || (_onReceiveCB != NULL && _onReceiveTimeout))) {
fifoFull = 120; fifoFull = 120;
} }
uartSetRxFIFOFull(_uart, fifoFull); uartSetRxFIFOFull(_uart, fifoFull);
@ -477,6 +498,12 @@ void HardwareSerial::setDebugOutput(bool en) {
if (_uart == 0) { if (_uart == 0) {
return; return;
} }
#if (SOC_UART_LP_NUM >= 1)
if (_uart_nr >= SOC_UART_HP_NUM) {
log_e("LP UART does not support Debug Output.");
return;
}
#endif
if (en) { if (en) {
uartSetDebug(_uart); uartSetDebug(_uart);
} else { } else {
@ -580,35 +607,56 @@ bool HardwareSerial::setMode(SerialMode mode) {
return uartSetMode(_uart, mode); return uartSetMode(_uart, mode);
} }
// Sets the UART Clock Source based on the compatible SoC options
// This method must be called before starting UART using begin(), otherwise it won't have any effect.
// Clock Source Options are:
// UART_CLK_SRC_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source
// UART_CLK_SRC_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3
// UART_CLK_SRC_PLL :: ESP32-C2, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 and ESP32-P4
// UART_CLK_SRC_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
// UART_CLK_SRC_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
// UART_CLK_SRC_REF_TICK :: ESP32 and ESP32-S2
// Note: CLK_SRC_PLL Freq depends on the SoC - ESP32-C2 has 40MHz, ESP32-H2 has 48MHz and ESP32-C5, C6, C61 and P4 has 80MHz
// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only RTC_FAST or XTAL/2 as Clock Source
bool HardwareSerial::setClockSource(SerialClkSrc clkSrc) {
if (_uart) {
log_e("No Clock Source change was done. This function must be called before beginning UART%d.", _uart_nr);
return false;
}
return uartSetClockSource(_uart_nr, (uart_sclk_t)clkSrc);
}
// minimum total RX Buffer size is the UART FIFO space (128 bytes for most SoC) + 1. IDF imposition. // minimum total RX Buffer size is the UART FIFO space (128 bytes for most SoC) + 1. IDF imposition.
// LP UART has FIFO of 16 bytes
size_t HardwareSerial::setRxBufferSize(size_t new_size) { size_t HardwareSerial::setRxBufferSize(size_t new_size) {
if (_uart) { if (_uart) {
log_e("RX Buffer can't be resized when Serial is already running. Set it before calling begin()."); log_e("RX Buffer can't be resized when Serial is already running. Set it before calling begin().");
return 0; return 0;
} }
uint8_t FIFOLen = UART_HW_FIFO_LEN(_uart_nr);
if (new_size <= SOC_UART_FIFO_LEN) { // Valid value is higher than the FIFO length
log_w("RX Buffer set to minimum value: %d.", SOC_UART_FIFO_LEN + 1); // ESP32, S2, S3 and C3 means higher than 128 if (new_size <= FIFOLen) {
new_size = SOC_UART_FIFO_LEN + 1; new_size = FIFOLen + 1;
log_w("RX Buffer set to minimum value: %d.", new_size);
} }
_rxBufferSize = new_size; _rxBufferSize = new_size;
return _rxBufferSize; return _rxBufferSize;
} }
// minimum total TX Buffer size is the UART FIFO space (128 bytes for most SoC). // minimum total TX Buffer size is the UART FIFO space (128 bytes for most SoC) + 1.
// LP UART has FIFO of 16 bytes
size_t HardwareSerial::setTxBufferSize(size_t new_size) { size_t HardwareSerial::setTxBufferSize(size_t new_size) {
if (_uart) { if (_uart) {
log_e("TX Buffer can't be resized when Serial is already running. Set it before calling begin()."); log_e("TX Buffer can't be resized when Serial is already running. Set it before calling begin().");
return 0; return 0;
} }
uint8_t FIFOLen = UART_HW_FIFO_LEN(_uart_nr);
if (new_size <= SOC_UART_FIFO_LEN) { // Valid values are zero or higher than the FIFO length
log_w("TX Buffer set to minimum value: %d.", SOC_UART_FIFO_LEN); // ESP32, S2, S3 and C3 means higher than 128 if (new_size > 0 && new_size <= FIFOLen) {
_txBufferSize = 0; // it will use just UART FIFO with SOC_UART_FIFO_LEN bytes (128 for most SoC) new_size = FIFOLen + 1;
return SOC_UART_FIFO_LEN; log_w("TX Buffer set to minimum value: %d.", new_size);
} }
// if new_size is higher than SOC_UART_FIFO_LEN, TX Ringbuffer will be active and it will be used to report back "availableToWrite()" // if new_size is higher than SOC_UART_FIFO_LEN, TX Ringbuffer will be active and it will be used to report back "availableToWrite()"
_txBufferSize = new_size; _txBufferSize = new_size;

View file

@ -96,16 +96,51 @@ typedef enum {
UART_PARITY_ERROR UART_PARITY_ERROR
} hardwareSerial_error_t; } hardwareSerial_error_t;
typedef enum {
UART_CLK_SRC_DEFAULT = UART_SCLK_DEFAULT,
#if SOC_UART_SUPPORT_APB_CLK
UART_CLK_SRC_APB = UART_SCLK_APB,
#endif
#if SOC_UART_SUPPORT_PLL_F40M_CLK
UART_CLK_SRC_PLL = UART_SCLK_PLL_F40M,
#elif SOC_UART_SUPPORT_PLL_F80M_CLK
UART_CLK_SRC_PLL = UART_SCLK_PLL_F80M,
#elif CONFIG_IDF_TARGET_ESP32H2
UART_CLK_SRC_PLL = UART_SCLK_PLL_F48M,
#endif
#if SOC_UART_SUPPORT_XTAL_CLK
UART_CLK_SRC_XTAL = UART_SCLK_XTAL,
#endif
#if SOC_UART_SUPPORT_RTC_CLK
UART_CLK_SRC_RTC = UART_SCLK_RTC,
#endif
#if SOC_UART_SUPPORT_REF_TICK
UART_CLK_SRC_REF_TICK = UART_SCLK_REF_TICK,
#endif
} SerialClkSrc;
#ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE #ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
#ifndef CONFIG_ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
#define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048 #define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048
#else
#define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE CONFIG_ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
#endif
#endif #endif
#ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY #ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY
#ifndef CONFIG_ARDUINO_SERIAL_EVENT_TASK_PRIORITY
#define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES - 1) #define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#else
#define ARDUINO_SERIAL_EVENT_TASK_PRIORITY CONFIG_ARDUINO_SERIAL_EVENT_TASK_PRIORITY
#endif
#endif #endif
#ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE #ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
#ifndef CONFIG_ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
#define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1 #define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1
#else
#define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE CONFIG_ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
#endif
#endif #endif
// UART0 pins are defined by default by the bootloader. // UART0 pins are defined by default by the bootloader.
@ -212,6 +247,16 @@ typedef enum {
#endif #endif
#endif /* SOC_UART_HP_NUM > 2 */ #endif /* SOC_UART_HP_NUM > 2 */
#if SOC_UART_LP_NUM >= 1
#ifndef LP_RX0
#define LP_RX0 (gpio_num_t) LP_U0RXD_GPIO_NUM
#endif
#ifndef LP_TX0
#define LP_TX0 (gpio_num_t) LP_U0TXD_GPIO_NUM
#endif
#endif /* SOC_UART_LP_NUM >= 1 */
typedef std::function<void(void)> OnReceiveCb; typedef std::function<void(void)> OnReceiveCb;
typedef std::function<void(hardwareSerial_error_t)> OnReceiveErrorCb; typedef std::function<void(hardwareSerial_error_t)> OnReceiveErrorCb;
@ -259,7 +304,7 @@ public:
// rxfifo_full_thrhd if the UART Flow Control Threshold in the UART FIFO (max 127) // rxfifo_full_thrhd if the UART Flow Control Threshold in the UART FIFO (max 127)
void begin( void begin(
unsigned long baud, uint32_t config = SERIAL_8N1, int8_t rxPin = -1, int8_t txPin = -1, bool invert = false, unsigned long timeout_ms = 20000UL, unsigned long baud, uint32_t config = SERIAL_8N1, int8_t rxPin = -1, int8_t txPin = -1, bool invert = false, unsigned long timeout_ms = 20000UL,
uint8_t rxfifo_full_thrhd = 112 uint8_t rxfifo_full_thrhd = 120
); );
void end(void); void end(void);
void updateBaudRate(unsigned long baud); void updateBaudRate(unsigned long baud);
@ -322,6 +367,17 @@ public:
// UART_MODE_RS485_COLLISION_DETECT = 0x03 mode: RS485 collision detection UART mode (used for test purposes) // UART_MODE_RS485_COLLISION_DETECT = 0x03 mode: RS485 collision detection UART mode (used for test purposes)
// UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes) // UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes)
bool setMode(SerialMode mode); bool setMode(SerialMode mode);
// Used to set the UART clock source mode. It must be set before calling begin(), otherwise it won't have any effect.
// Not all clock source are available to every SoC. The compatible option are listed here:
// UART_CLK_SRC_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source
// UART_CLK_SRC_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3
// UART_CLK_SRC_PLL :: ESP32-C2, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 and ESP32-P4
// UART_CLK_SRC_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
// UART_CLK_SRC_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
// UART_CLK_SRC_REF_TICK :: ESP32 and ESP32-S2
// Note: CLK_SRC_PLL Freq depends on the SoC - ESP32-C2 has 40MHz, ESP32-H2 has 48MHz and ESP32-C5, C6, C61 and P4 has 80MHz
// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only RTC_FAST or XTAL/2 as Clock Source
bool setClockSource(SerialClkSrc clkSrc);
size_t setRxBufferSize(size_t new_size); size_t setRxBufferSize(size_t new_size);
size_t setTxBufferSize(size_t new_size); size_t setTxBufferSize(size_t new_size);
@ -365,18 +421,21 @@ extern void serialEventRun(void) __attribute__((weak));
#endif // ARDUINO_USB_CDC_ON_BOOT #endif // ARDUINO_USB_CDC_ON_BOOT
// There is always Seria0 for UART0 // There is always Seria0 for UART0
extern HardwareSerial Serial0; extern HardwareSerial Serial0;
#if SOC_UART_HP_NUM > 1 #if SOC_UART_NUM > 1
extern HardwareSerial Serial1; extern HardwareSerial Serial1;
#endif #endif
#if SOC_UART_HP_NUM > 2 #if SOC_UART_NUM > 2
extern HardwareSerial Serial2; extern HardwareSerial Serial2;
#endif #endif
#if SOC_UART_HP_NUM > 3 #if SOC_UART_NUM > 3
extern HardwareSerial Serial3; extern HardwareSerial Serial3;
#endif #endif
#if SOC_UART_HP_NUM > 4 #if SOC_UART_NUM > 4
extern HardwareSerial Serial4; extern HardwareSerial Serial4;
#endif #endif
#if SOC_UART_NUM > 5
extern HardwareSerial Serial5;
#endif
#endif //!defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) #endif //!defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
#endif // HardwareSerial_h #endif // HardwareSerial_h

View file

@ -100,6 +100,7 @@ static bool tinyusb_device_suspended = false;
void tud_mount_cb(void) { void tud_mount_cb(void) {
tinyusb_device_mounted = true; tinyusb_device_mounted = true;
arduino_usb_event_data_t p; arduino_usb_event_data_t p;
p.suspend.remote_wakeup_en = 0;
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
} }
@ -107,6 +108,7 @@ void tud_mount_cb(void) {
void tud_umount_cb(void) { void tud_umount_cb(void) {
tinyusb_device_mounted = false; tinyusb_device_mounted = false;
arduino_usb_event_data_t p; arduino_usb_event_data_t p;
p.suspend.remote_wakeup_en = 0;
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
} }
@ -123,6 +125,7 @@ void tud_suspend_cb(bool remote_wakeup_en) {
void tud_resume_cb(void) { void tud_resume_cb(void) {
tinyusb_device_suspended = false; tinyusb_device_suspended = false;
arduino_usb_event_data_t p; arduino_usb_event_data_t p;
p.suspend.remote_wakeup_en = 0;
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
} }

View file

@ -25,8 +25,7 @@ ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS);
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
#define MAX_USB_CDC_DEVICES 2 USBCDC *devices[CFG_TUD_CDC];
USBCDC *devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
static uint16_t load_cdc_descriptor(uint8_t *dst, uint8_t *itf) { static uint16_t load_cdc_descriptor(uint8_t *dst, uint8_t *itf) {
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC"); uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC");
@ -38,23 +37,43 @@ static uint16_t load_cdc_descriptor(uint8_t *dst, uint8_t *itf) {
return TUD_CDC_DESC_LEN; return TUD_CDC_DESC_LEN;
} }
static uint16_t load_cdc_descriptor2(uint8_t *dst, uint8_t *itf) {
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC2");
uint8_t ep_ntfy = tinyusb_get_free_in_endpoint();
TU_VERIFY(ep_ntfy != 0);
uint8_t ep_in = tinyusb_get_free_in_endpoint();
TU_VERIFY(ep_in != 0);
uint8_t ep_out = tinyusb_get_free_out_endpoint();
TU_VERIFY(ep_out != 0);
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, (uint8_t)(0x80 | ep_ntfy), CFG_TUD_ENDOINT_SIZE, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE)
};
*itf += 2;
memcpy(dst, descriptor, TUD_CDC_DESC_LEN);
return TUD_CDC_DESC_LEN;
}
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE // Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) { //log_v("ITF: %u, DTR: %u, RTS: %u", itf, dtr, rts);
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
devices[itf]->_onLineState(dtr, rts); devices[itf]->_onLineState(dtr, rts);
} }
} }
// Invoked when line coding is change via SET_LINE_CODING // Invoked when line coding is change via SET_LINE_CODING
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *p_line_coding) { void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *p_line_coding) {
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) { //log_v("ITF: %u, BITRATE: %lu, STOP_BITS: %u, PARITY: %u, DATA_BITS: %u", itf, p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits); devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
} }
} }
// Invoked when received new data // Invoked when received new data
void tud_cdc_rx_cb(uint8_t itf) { void tud_cdc_rx_cb(uint8_t itf) {
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) { //log_v("ITF: %u", itf);
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
devices[itf]->_onRX(); devices[itf]->_onRX();
} }
} }
@ -66,13 +85,13 @@ void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) {
// Invoked when space becomes available in TX buffer // Invoked when space becomes available in TX buffer
void tud_cdc_tx_complete_cb(uint8_t itf) { void tud_cdc_tx_complete_cb(uint8_t itf) {
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) { if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
devices[itf]->_onTX(); devices[itf]->_onTX();
} }
} }
static void ARDUINO_ISR_ATTR cdc0_write_char(char c) { static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
if (devices[0] != NULL) { if (CFG_TUD_CDC && devices[0] != NULL) {
tud_cdc_n_write_char(0, c); tud_cdc_n_write_char(0, c);
} }
} }
@ -84,9 +103,15 @@ static void usb_unplugged_cb(void *arg, esp_event_base_t event_base, int32_t eve
USBCDC::USBCDC(uint8_t itfn) USBCDC::USBCDC(uint8_t itfn)
: itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL), tx_lock(NULL), : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL), tx_lock(NULL),
tx_timeout_ms(250) { tx_timeout_ms(250) {
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor); if (itf < CFG_TUD_CDC) {
if (itf < MAX_USB_CDC_DEVICES) { if (itf == 0) {
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
} else {
tinyusb_enable_interface(USB_INTERFACE_CDC2, TUD_CDC_DESC_LEN, load_cdc_descriptor2);
}
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this); arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this);
} else {
log_e("Maximum of %u CDC devices are supported", CFG_TUD_CDC);
} }
} }
@ -142,6 +167,9 @@ size_t USBCDC::setRxBufferSize(size_t rx_queue_len) {
} }
void USBCDC::begin(unsigned long baud) { void USBCDC::begin(unsigned long baud) {
if (itf >= CFG_TUD_CDC) {
return;
}
if (tx_lock == NULL) { if (tx_lock == NULL) {
tx_lock = xSemaphoreCreateMutex(); tx_lock = xSemaphoreCreateMutex();
} }
@ -153,6 +181,9 @@ void USBCDC::begin(unsigned long baud) {
} }
void USBCDC::end() { void USBCDC::end() {
if (itf >= CFG_TUD_CDC) {
return;
}
connected = false; connected = false;
devices[itf] = NULL; devices[itf] = NULL;
setRxBufferSize(0); setRxBufferSize(0);
@ -298,14 +329,14 @@ bool USBCDC::rebootEnabled(void) {
} }
int USBCDC::available(void) { int USBCDC::available(void) {
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) { if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
return -1; return -1;
} }
return uxQueueMessagesWaiting(rx_queue); return uxQueueMessagesWaiting(rx_queue);
} }
int USBCDC::peek(void) { int USBCDC::peek(void) {
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) { if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
return -1; return -1;
} }
uint8_t c; uint8_t c;
@ -316,7 +347,7 @@ int USBCDC::peek(void) {
} }
int USBCDC::read(void) { int USBCDC::read(void) {
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) { if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
return -1; return -1;
} }
uint8_t c = 0; uint8_t c = 0;
@ -327,7 +358,7 @@ int USBCDC::read(void) {
} }
size_t USBCDC::read(uint8_t *buffer, size_t size) { size_t USBCDC::read(uint8_t *buffer, size_t size) {
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) { if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
return -1; return -1;
} }
uint8_t c = 0; uint8_t c = 0;
@ -339,7 +370,7 @@ size_t USBCDC::read(uint8_t *buffer, size_t size) {
} }
void USBCDC::flush(void) { void USBCDC::flush(void) {
if (itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)) { if (itf >= CFG_TUD_CDC || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
return; return;
} }
if (xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS) { if (xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS) {
@ -350,7 +381,7 @@ void USBCDC::flush(void) {
} }
int USBCDC::availableForWrite(void) { int USBCDC::availableForWrite(void) {
if (itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)) { if (itf >= CFG_TUD_CDC || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
return 0; return 0;
} }
if (xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS) { if (xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS) {
@ -362,7 +393,7 @@ int USBCDC::availableForWrite(void) {
} }
size_t USBCDC::write(const uint8_t *buffer, size_t size) { size_t USBCDC::write(const uint8_t *buffer, size_t size) {
if (itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)) { if (itf >= CFG_TUD_CDC || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)) {
return 0; return 0;
} }
if (xPortInIsrContext()) { if (xPortInIsrContext()) {
@ -415,16 +446,20 @@ uint32_t USBCDC::baudRate() {
} }
void USBCDC::setDebugOutput(bool en) { void USBCDC::setDebugOutput(bool en) {
if (itf) {
return;
}
if (en) { if (en) {
uartSetDebug(NULL); uartSetDebug(NULL);
ets_install_putc2((void (*)(char)) & cdc0_write_char); ets_install_putc2((void (*)(char)) & cdc0_write_char);
} else { } else {
ets_install_putc2(NULL); ets_install_putc2(NULL);
} }
ets_install_putc1(NULL); // closes UART log output
} }
USBCDC::operator bool() const { USBCDC::operator bool() const {
if (itf >= MAX_USB_CDC_DEVICES) { if (itf >= CFG_TUD_CDC) {
return false; return false;
} }
return connected; return connected;

View file

@ -226,11 +226,11 @@ bool String::changeBuffer(unsigned int maxStrLen) {
/*********************************************/ /*********************************************/
String &String::copy(const char *cstr, unsigned int length) { String &String::copy(const char *cstr, unsigned int length) {
if (!reserve(length)) { if (cstr == nullptr || !reserve(length)) {
invalidate(); invalidate();
return *this; return *this;
} }
memmove(wbuffer(), cstr, length + 1); memmove(wbuffer(), cstr, length);
setLen(length); setLen(length);
return *this; return *this;
} }
@ -239,15 +239,18 @@ String &String::copy(const char *cstr, unsigned int length) {
void String::move(String &rhs) { void String::move(String &rhs) {
if (buffer()) { if (buffer()) {
if (capacity() >= rhs.len()) { if (capacity() >= rhs.len()) {
memmove(wbuffer(), rhs.buffer(), rhs.length() + 1); // Use case: When 'reserve()' was called and the first
// assignment/append is the return value of a function.
if (rhs.len() && rhs.buffer()) {
memmove(wbuffer(), rhs.buffer(), rhs.length());
}
setLen(rhs.len()); setLen(rhs.len());
rhs.invalidate(); rhs.invalidate();
return; return;
} else { }
if (!isSSO()) { if (!isSSO()) {
free(wbuffer()); free(wbuffer());
setBuffer(nullptr); setBuffer(nullptr);
}
} }
} }
if (rhs.isSSO()) { if (rhs.isSSO()) {
@ -259,10 +262,7 @@ void String::move(String &rhs) {
} }
setCapacity(rhs.capacity()); setCapacity(rhs.capacity());
setLen(rhs.len()); setLen(rhs.len());
rhs.setSSO(false); rhs.init();
rhs.setCapacity(0);
rhs.setBuffer(nullptr);
rhs.setLen(0);
} }
#endif #endif
@ -270,12 +270,7 @@ String &String::operator=(const String &rhs) {
if (this == &rhs) { if (this == &rhs) {
return *this; return *this;
} }
if (rhs.buffer()) { return copy(rhs.buffer(), rhs.len());
copy(rhs.buffer(), rhs.len());
} else {
invalidate();
}
return *this;
} }
#ifdef __GXX_EXPERIMENTAL_CXX0X__ #ifdef __GXX_EXPERIMENTAL_CXX0X__
@ -295,12 +290,8 @@ String &String::operator=(StringSumHelper &&rval) {
#endif #endif
String &String::operator=(const char *cstr) { String &String::operator=(const char *cstr) {
if (cstr) { const uint32_t length = cstr ? strlen(cstr) : 0u;
copy(cstr, strlen(cstr)); return copy(cstr, length);
} else {
invalidate();
}
return *this;
} }
/*********************************************/ /*********************************************/
@ -311,23 +302,21 @@ bool String::concat(const String &s) {
// Special case if we're concatting ourself (s += s;) since we may end up // Special case if we're concatting ourself (s += s;) since we may end up
// realloc'ing the buffer and moving s.buffer in the method called // realloc'ing the buffer and moving s.buffer in the method called
if (&s == this) { if (&s == this) {
unsigned int newlen = 2 * len();
if (!s.buffer()) {
return false;
}
if (s.len() == 0) { if (s.len() == 0) {
return true; return true;
} }
if (!s.buffer()) {
return false;
}
unsigned int newlen = 2 * len();
if (!reserve(newlen)) { if (!reserve(newlen)) {
return false; return false;
} }
memmove(wbuffer() + len(), buffer(), len()); memmove(wbuffer() + len(), buffer(), len());
setLen(newlen); setLen(newlen);
wbuffer()[len()] = 0;
return true; return true;
} else {
return concat(s.buffer(), s.len());
} }
return concat(s.buffer(), s.len());
} }
bool String::concat(const char *cstr, unsigned int length) { bool String::concat(const char *cstr, unsigned int length) {
@ -343,10 +332,10 @@ bool String::concat(const char *cstr, unsigned int length) {
} }
if (cstr >= wbuffer() && cstr < wbuffer() + len()) { if (cstr >= wbuffer() && cstr < wbuffer() + len()) {
// compatible with SSO in ram #6155 (case "x += x.c_str()") // compatible with SSO in ram #6155 (case "x += x.c_str()")
memmove(wbuffer() + len(), cstr, length + 1); memmove(wbuffer() + len(), cstr, length);
} else { } else {
// compatible with source in flash #6367 // compatible with source in flash #6367
memcpy_P(wbuffer() + len(), cstr, length + 1); memcpy_P(wbuffer() + len(), cstr, length);
} }
setLen(newlen); setLen(newlen);
return true; return true;

View file

@ -15,7 +15,7 @@
#include "esp32-hal-bt.h" #include "esp32-hal-bt.h"
#if SOC_BT_SUPPORTED #if SOC_BT_SUPPORTED
#ifdef CONFIG_BT_ENABLED #ifdef CONFIG_BT_BLUEDROID_ENABLED
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
bool btInUse() { bool btInUse() {

View file

@ -173,7 +173,7 @@ extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val) {
if (perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) != NULL) { if (perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) != NULL) {
gpio_set_level((gpio_num_t)pin, val); gpio_set_level((gpio_num_t)pin, val);
} else { } else {
log_e("IO %i is not set as GPIO.", pin); log_e("IO %i is not set as GPIO. Execute digitalMode(%i, OUTPUT) first.", pin, pin);
} }
} }
@ -182,14 +182,12 @@ extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin) {
if (pin == RGB_BUILTIN) { if (pin == RGB_BUILTIN) {
return RGB_BUILTIN_storage; return RGB_BUILTIN_storage;
} }
#endif #endif // RGB_BUILTIN
// This work when the pin is set as GPIO and in INPUT mode. For all other pin functions, it may return inconsistent response
if (perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) != NULL) { if (perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) == NULL) {
return gpio_get_level((gpio_num_t)pin); log_w("IO %i is not set as GPIO. digitalRead() may return an inconsistent value.", pin);
} else {
log_e("IO %i is not set as GPIO.", pin);
return 0;
} }
return gpio_get_level((gpio_num_t)pin);
} }
static void ARDUINO_ISR_ATTR __onPinInterrupt(void *arg) { static void ARDUINO_ISR_ATTR __onPinInterrupt(void *arg) {

View file

@ -0,0 +1,445 @@
// Copyright 2015-2025 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 "esp32-hal-i2c.h"
#if SOC_I2C_SUPPORTED
#include "esp_idf_version.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
#include "esp32-hal.h"
#if !CONFIG_DISABLE_HAL_LOCKS
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#endif
#include "esp_attr.h"
#include "esp_system.h"
#include "soc/soc_caps.h"
#include "driver/i2c_master.h"
#include "esp32-hal-periman.h"
typedef volatile struct {
bool initialized;
uint32_t frequency;
#if !CONFIG_DISABLE_HAL_LOCKS
SemaphoreHandle_t lock;
#endif
int8_t scl;
int8_t sda;
i2c_master_bus_handle_t bus_handle;
i2c_master_dev_handle_t dev_handles[128];
} i2c_bus_t;
static i2c_bus_t bus[SOC_I2C_NUM];
static bool i2cDetachBus(void *bus_i2c_num) {
uint8_t i2c_num = (int)bus_i2c_num - 1;
if (!bus[i2c_num].initialized) {
return true;
}
esp_err_t err = i2cDeinit(i2c_num);
if (err != ESP_OK) {
log_e("i2cDeinit failed with error: %d", err);
return false;
}
return true;
}
bool i2cIsInit(uint8_t i2c_num) {
if (i2c_num >= SOC_I2C_NUM) {
return false;
}
return bus[i2c_num].initialized;
}
esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) {
esp_err_t ret = ESP_OK;
if (i2c_num >= SOC_I2C_NUM) {
return ESP_ERR_INVALID_ARG;
}
#if !CONFIG_DISABLE_HAL_LOCKS
if (bus[i2c_num].lock == NULL) {
bus[i2c_num].lock = xSemaphoreCreateMutex();
if (bus[i2c_num].lock == NULL) {
log_e("xSemaphoreCreateMutex failed");
return ESP_ERR_NO_MEM;
}
}
//acquire lock
if (xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return ESP_FAIL;
}
#endif
if (bus[i2c_num].initialized) {
log_e("bus is already initialized");
ret = ESP_FAIL;
goto init_fail;
}
if (!frequency) {
frequency = 100000UL;
} else if (frequency > 1000000UL) {
frequency = 1000000UL;
}
perimanSetBusDeinit(ESP32_BUS_TYPE_I2C_MASTER_SDA, i2cDetachBus);
perimanSetBusDeinit(ESP32_BUS_TYPE_I2C_MASTER_SCL, i2cDetachBus);
if (!perimanClearPinBus(sda) || !perimanClearPinBus(scl)) {
ret = ESP_FAIL;
goto init_fail;
}
log_i("Initializing I2C Master: num=%u sda=%d scl=%d freq=%lu", i2c_num, sda, scl, frequency);
i2c_master_bus_handle_t bus_handle = NULL;
i2c_master_bus_config_t bus_config;
memset(&bus_config, 0, sizeof(i2c_master_bus_config_t));
bus_config.i2c_port = (i2c_port_num_t)i2c_num;
bus_config.sda_io_num = (gpio_num_t)sda;
bus_config.scl_io_num = (gpio_num_t)scl;
#if SOC_LP_I2C_SUPPORTED
if (i2c_num >= SOC_HP_I2C_NUM) {
bus_config.lp_source_clk = LP_I2C_SCLK_DEFAULT;
} else
#endif
{
bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
}
bus_config.glitch_ignore_cnt = 7;
bus_config.intr_priority = 0; // auto
bus_config.trans_queue_depth = 0; // only valid in asynchronous transaction, which Arduino does not use
bus_config.flags.enable_internal_pullup = 1;
#if SOC_I2C_SUPPORT_SLEEP_RETENTION
bus_config.flags.allow_pd = 1; // backup/restore the I2C registers before/after entering/exist sleep mode
#endif
ret = i2c_new_master_bus(&bus_config, &bus_handle);
if (ret != ESP_OK) {
log_e("i2c_new_master_bus failed: [%d] %s", ret, esp_err_to_name(ret));
} else {
bus[i2c_num].initialized = true;
bus[i2c_num].frequency = frequency;
bus[i2c_num].scl = scl;
bus[i2c_num].sda = sda;
bus[i2c_num].bus_handle = bus_handle;
for (uint8_t i = 0; i < 128; i++) {
bus[i2c_num].dev_handles[i] = NULL;
}
if (!perimanSetPinBus(sda, ESP32_BUS_TYPE_I2C_MASTER_SDA, (void *)(i2c_num + 1), i2c_num, -1)
|| !perimanSetPinBus(scl, ESP32_BUS_TYPE_I2C_MASTER_SCL, (void *)(i2c_num + 1), i2c_num, -1)) {
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock so that i2cDetachBus can execute i2cDeinit
xSemaphoreGive(bus[i2c_num].lock);
#endif
i2cDetachBus((void *)(i2c_num + 1));
return ESP_FAIL;
}
}
init_fail:
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(bus[i2c_num].lock);
#endif
return ret;
}
esp_err_t i2cDeinit(uint8_t i2c_num) {
esp_err_t err = ESP_FAIL;
if (i2c_num >= SOC_I2C_NUM) {
return ESP_ERR_INVALID_ARG;
}
#if !CONFIG_DISABLE_HAL_LOCKS
//acquire lock
if (bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return err;
}
#endif
if (!bus[i2c_num].initialized) {
log_e("bus is not initialized");
} else {
// remove devices from the bus
for (uint8_t i = 0; i < 128; i++) {
if (bus[i2c_num].dev_handles[i] != NULL) {
err = i2c_master_bus_rm_device(bus[i2c_num].dev_handles[i]);
bus[i2c_num].dev_handles[i] = NULL;
if (err != ESP_OK) {
log_e("i2c_master_bus_rm_device failed: [%d] %s", err, esp_err_to_name(err));
}
}
}
err = i2c_del_master_bus(bus[i2c_num].bus_handle);
if (err != ESP_OK) {
log_e("i2c_del_master_bus failed: [%d] %s", err, esp_err_to_name(err));
} else {
bus[i2c_num].initialized = false;
perimanClearPinBus(bus[i2c_num].scl);
perimanClearPinBus(bus[i2c_num].sda);
bus[i2c_num].scl = -1;
bus[i2c_num].sda = -1;
bus[i2c_num].bus_handle = NULL;
}
}
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(bus[i2c_num].lock);
#endif
return err;
}
static esp_err_t i2cAddDeviceIfNeeded(uint8_t i2c_num, uint16_t address) {
esp_err_t ret = ESP_OK;
if (bus[i2c_num].dev_handles[address] == NULL) {
i2c_master_dev_handle_t dev_handle = NULL;
i2c_device_config_t dev_config;
memset(&dev_config, 0, sizeof(i2c_device_config_t));
dev_config.dev_addr_length = I2C_ADDR_BIT_LEN_7; // Arduino supports only 7bit addresses
dev_config.device_address = address;
dev_config.scl_speed_hz = bus[i2c_num].frequency;
dev_config.scl_wait_us = 0;
dev_config.flags.disable_ack_check = 0;
ret = i2c_master_bus_add_device(bus[i2c_num].bus_handle, &dev_config, &dev_handle);
if (ret != ESP_OK) {
log_e("i2c_master_bus_add_device failed: [%d] %s", ret, esp_err_to_name(ret));
} else {
bus[i2c_num].dev_handles[address] = dev_handle;
log_v("added device: bus=%u addr=0x%x handle=0x%08x", i2c_num, address, dev_handle);
}
}
return ret;
}
esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t *buff, size_t size, uint32_t timeOutMillis) {
esp_err_t ret = ESP_FAIL;
// i2c_cmd_handle_t cmd = NULL;
if (i2c_num >= SOC_I2C_NUM) {
return ESP_ERR_INVALID_ARG;
}
if (address >= 128) {
log_e("Only 7bit I2C addresses are supported");
return ESP_ERR_INVALID_ARG;
}
#if !CONFIG_DISABLE_HAL_LOCKS
//acquire lock
if (bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return ret;
}
#endif
if (!bus[i2c_num].initialized) {
log_e("bus is not initialized");
goto end;
}
if (size == 0) {
// Probe device
ret = i2c_master_probe(bus[i2c_num].bus_handle, address, timeOutMillis);
if (ret != ESP_OK) {
log_v("i2c_master_probe failed: [%d] %s", ret, esp_err_to_name(ret));
}
} else {
// writing data to device
ret = i2cAddDeviceIfNeeded(i2c_num, address);
if (ret != ESP_OK) {
goto end;
}
log_v("i2c_master_transmit: bus=%u addr=0x%x handle=0x%08x size=%u", i2c_num, address, bus[i2c_num].dev_handles[address], size);
ret = i2c_master_transmit(bus[i2c_num].dev_handles[address], buff, size, timeOutMillis);
if (ret != ESP_OK) {
log_e("i2c_master_transmit failed: [%d] %s", ret, esp_err_to_name(ret));
goto end;
}
// wait for transactions to finish (is it needed with sync transactions?)
// ret = i2c_master_bus_wait_all_done(bus[i2c_num].bus_handle, timeOutMillis);
// if (ret != ESP_OK) {
// log_e("i2c_master_bus_wait_all_done failed: [%d] %s", ret, esp_err_to_name(ret));
// goto end;
// }
}
end:
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(bus[i2c_num].lock);
#endif
return ret;
}
esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t *buff, size_t size, uint32_t timeOutMillis, size_t *readCount) {
esp_err_t ret = ESP_FAIL;
*readCount = 0;
if (i2c_num >= SOC_I2C_NUM) {
return ESP_ERR_INVALID_ARG;
}
#if !CONFIG_DISABLE_HAL_LOCKS
//acquire lock
if (bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return ret;
}
#endif
if (!bus[i2c_num].initialized) {
log_e("bus is not initialized");
goto end;
}
ret = i2cAddDeviceIfNeeded(i2c_num, address);
if (ret != ESP_OK) {
goto end;
}
log_v("i2c_master_receive: bus=%u addr=0x%x handle=0x%08x size=%u", i2c_num, address, bus[i2c_num].dev_handles[address], size);
ret = i2c_master_receive(bus[i2c_num].dev_handles[address], buff, size, timeOutMillis);
if (ret != ESP_OK) {
log_e("i2c_master_receive failed: [%d] %s", ret, esp_err_to_name(ret));
goto end;
}
// wait for transactions to finish (is it needed with sync transactions?)
// ret = i2c_master_bus_wait_all_done(bus[i2c_num].bus_handle, timeOutMillis);
// if (ret != ESP_OK) {
// log_e("i2c_master_bus_wait_all_done failed: [%d] %s", ret, esp_err_to_name(ret));
// goto end;
// }
*readCount = size;
end:
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(bus[i2c_num].lock);
#endif
return ret;
}
esp_err_t i2cWriteReadNonStop(
uint8_t i2c_num, uint16_t address, const uint8_t *wbuff, size_t wsize, uint8_t *rbuff, size_t rsize, uint32_t timeOutMillis, size_t *readCount
) {
esp_err_t ret = ESP_FAIL;
*readCount = 0;
if (i2c_num >= SOC_I2C_NUM) {
return ESP_ERR_INVALID_ARG;
}
#if !CONFIG_DISABLE_HAL_LOCKS
//acquire lock
if (bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return ret;
}
#endif
if (!bus[i2c_num].initialized) {
log_e("bus is not initialized");
goto end;
}
ret = i2cAddDeviceIfNeeded(i2c_num, address);
if (ret != ESP_OK) {
goto end;
}
log_v("i2c_master_transmit_receive: bus=%u addr=0x%x handle=0x%08x write=%u read=%u", i2c_num, address, bus[i2c_num].dev_handles[address], wsize, rsize);
ret = i2c_master_transmit_receive(bus[i2c_num].dev_handles[address], wbuff, wsize, rbuff, rsize, timeOutMillis);
if (ret != ESP_OK) {
log_e("i2c_master_transmit_receive failed: [%d] %s", ret, esp_err_to_name(ret));
goto end;
}
// wait for transactions to finish (is it needed with sync transactions?)
// ret = i2c_master_bus_wait_all_done(bus[i2c_num].bus_handle, timeOutMillis);
// if (ret != ESP_OK) {
// log_e("i2c_master_bus_wait_all_done failed: [%d] %s", ret, esp_err_to_name(ret));
// goto end;
// }
*readCount = rsize;
end:
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(bus[i2c_num].lock);
#endif
return ret;
}
esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency) {
esp_err_t ret = ESP_FAIL;
if (i2c_num >= SOC_I2C_NUM) {
return ESP_ERR_INVALID_ARG;
}
#if !CONFIG_DISABLE_HAL_LOCKS
//acquire lock
if (bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return ret;
}
#endif
if (!bus[i2c_num].initialized) {
log_e("bus is not initialized");
goto end;
}
if (bus[i2c_num].frequency == frequency) {
ret = ESP_OK;
goto end;
}
if (!frequency) {
frequency = 100000UL;
} else if (frequency > 1000000UL) {
frequency = 1000000UL;
}
bus[i2c_num].frequency = frequency;
// loop through devices, remove them and then re-add them with the new frequency
for (uint8_t i = 0; i < 128; i++) {
if (bus[i2c_num].dev_handles[i] != NULL) {
ret = i2c_master_bus_rm_device(bus[i2c_num].dev_handles[i]);
if (ret != ESP_OK) {
log_e("i2c_master_bus_rm_device failed: [%d] %s", ret, esp_err_to_name(ret));
goto end;
} else {
bus[i2c_num].dev_handles[i] = NULL;
ret = i2cAddDeviceIfNeeded(i2c_num, i);
if (ret != ESP_OK) {
goto end;
}
}
}
}
end:
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(bus[i2c_num].lock);
#endif
return ret;
}
esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t *frequency) {
if (i2c_num >= SOC_I2C_NUM) {
return ESP_ERR_INVALID_ARG;
}
if (!bus[i2c_num].initialized) {
log_e("bus is not initialized");
return ESP_FAIL;
}
*frequency = bus[i2c_num].frequency;
return ESP_OK;
}
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0) */
#endif /* SOC_I2C_SUPPORTED */

View file

@ -336,7 +336,11 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t
#endif // !defined(CONFIG_IDF_TARGET_ESP32P4) #endif // !defined(CONFIG_IDF_TARGET_ESP32P4)
i2c_ll_slave_init(i2c->dev); i2c_ll_slave_init(i2c->dev);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
i2c_ll_enable_fifo_mode(i2c->dev, true);
#else
i2c_ll_slave_set_fifo_mode(i2c->dev, true); i2c_ll_slave_set_fifo_mode(i2c->dev, true);
#endif
i2c_ll_set_slave_addr(i2c->dev, slaveID, false); i2c_ll_set_slave_addr(i2c->dev, slaveID, false);
i2c_ll_set_tout(i2c->dev, I2C_LL_MAX_TIMEOUT); i2c_ll_set_tout(i2c->dev, I2C_LL_MAX_TIMEOUT);
i2c_slave_set_frequency(i2c, frequency); i2c_slave_set_frequency(i2c, frequency);
@ -357,7 +361,11 @@ 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_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK);
i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK); i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
i2c_ll_enable_fifo_mode(i2c->dev, true);
#else
i2c_ll_slave_set_fifo_mode(i2c->dev, true); i2c_ll_slave_set_fifo_mode(i2c->dev, true);
#endif
if (!i2c->intr_handle) { if (!i2c->intr_handle) {
uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED; uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED;

View file

@ -15,6 +15,8 @@
#include "esp32-hal-i2c.h" #include "esp32-hal-i2c.h"
#if SOC_I2C_SUPPORTED #if SOC_I2C_SUPPORTED
#include "esp_idf_version.h"
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0)
#include "esp32-hal.h" #include "esp32-hal.h"
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
@ -429,4 +431,5 @@ esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t *frequency) {
return ESP_OK; return ESP_OK;
} }
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) */
#endif /* SOC_I2C_SUPPORTED */ #endif /* SOC_I2C_SUPPORTED */

View file

@ -126,7 +126,14 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
return false; return false;
} }
} else { } else {
ledc_timer_config_t ledc_timer = {.speed_mode = group, .timer_num = timer, .duty_resolution = resolution, .freq_hz = freq, .clk_cfg = clock_source}; ledc_timer_config_t ledc_timer;
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
ledc_timer.speed_mode = group;
ledc_timer.timer_num = timer;
ledc_timer.duty_resolution = resolution;
ledc_timer.freq_hz = freq;
ledc_timer.clk_cfg = clock_source;
if (ledc_timer_config(&ledc_timer) != ESP_OK) { if (ledc_timer_config(&ledc_timer) != ESP_OK) {
log_e("ledc setup failed!"); log_e("ledc setup failed!");
return false; return false;
@ -134,9 +141,16 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
uint32_t duty = ledc_get_duty(group, (channel % 8)); uint32_t duty = ledc_get_duty(group, (channel % 8));
ledc_channel_config_t ledc_channel = { ledc_channel_config_t ledc_channel;
.speed_mode = group, .channel = (channel % 8), .timer_sel = timer, .intr_type = LEDC_INTR_DISABLE, .gpio_num = pin, .duty = duty, .hpoint = 0 memset((void *)&ledc_channel, 0, sizeof(ledc_channel_config_t));
}; ledc_channel.speed_mode = group;
ledc_channel.channel = (channel % 8);
ledc_channel.timer_sel = timer;
ledc_channel.intr_type = LEDC_INTR_DISABLE;
ledc_channel.gpio_num = pin;
ledc_channel.duty = duty;
ledc_channel.hpoint = 0;
ledc_channel_config(&ledc_channel); ledc_channel_config(&ledc_channel);
} }
@ -256,7 +270,13 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) {
uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4); uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4);
ledc_timer_config_t ledc_timer = {.speed_mode = group, .timer_num = timer, .duty_resolution = 10, .freq_hz = freq, .clk_cfg = clock_source}; ledc_timer_config_t ledc_timer;
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
ledc_timer.speed_mode = group;
ledc_timer.timer_num = timer;
ledc_timer.duty_resolution = 10;
ledc_timer.freq_hz = freq;
ledc_timer.clk_cfg = clock_source;
if (ledc_timer_config(&ledc_timer) != ESP_OK) { if (ledc_timer_config(&ledc_timer) != ESP_OK) {
log_e("ledcWriteTone configuration failed!"); log_e("ledcWriteTone configuration failed!");
@ -307,7 +327,13 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) {
} }
uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4); uint8_t group = (bus->channel / 8), timer = ((bus->channel / 2) % 4);
ledc_timer_config_t ledc_timer = {.speed_mode = group, .timer_num = timer, .duty_resolution = resolution, .freq_hz = freq, .clk_cfg = clock_source}; ledc_timer_config_t ledc_timer;
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
ledc_timer.speed_mode = group;
ledc_timer.timer_num = timer;
ledc_timer.duty_resolution = resolution;
ledc_timer.freq_hz = freq;
ledc_timer.clk_cfg = clock_source;
if (ledc_timer_config(&ledc_timer) != ESP_OK) { if (ledc_timer_config(&ledc_timer) != ESP_OK) {
log_e("ledcChangeFrequency failed!"); log_e("ledcChangeFrequency failed!");

View file

@ -25,9 +25,9 @@
#include "esp_ota_ops.h" #include "esp_ota_ops.h"
#endif //CONFIG_APP_ROLLBACK_ENABLE #endif //CONFIG_APP_ROLLBACK_ENABLE
#include "esp_private/startup_internal.h" #include "esp_private/startup_internal.h"
#ifdef CONFIG_BT_ENABLED #if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED
#include "esp_bt.h" #include "esp_bt.h"
#endif //CONFIG_BT_ENABLED #endif //CONFIG_BT_BLUEDROID_ENABLED
#include <sys/time.h> #include <sys/time.h>
#include "soc/rtc.h" #include "soc/rtc.h"
#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) #if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)
@ -156,11 +156,13 @@ void enableCore0WDT() {
} }
} }
void disableCore0WDT() { bool disableCore0WDT() {
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCore(0); TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCore(0);
if (idle_0 == NULL || esp_task_wdt_delete(idle_0) != ESP_OK) { if (idle_0 == NULL || esp_task_wdt_status(idle_0) || esp_task_wdt_delete(idle_0) != ESP_OK) {
log_e("Failed to remove Core 0 IDLE task from WDT"); log_e("Failed to remove Core 0 IDLE task from WDT");
return false;
} }
return true;
} }
#ifndef CONFIG_FREERTOS_UNICORE #ifndef CONFIG_FREERTOS_UNICORE
@ -171,11 +173,13 @@ void enableCore1WDT() {
} }
} }
void disableCore1WDT() { bool disableCore1WDT() {
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCore(1); TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCore(1);
if (idle_1 == NULL || esp_task_wdt_delete(idle_1) != ESP_OK) { if (idle_1 == NULL || esp_task_wdt_status(idle_1) || esp_task_wdt_delete(idle_1) != ESP_OK) {
log_e("Failed to remove Core 1 IDLE task from WDT"); log_e("Failed to remove Core 1 IDLE task from WDT");
return false;
} }
return true;
} }
#endif #endif
@ -239,7 +243,7 @@ bool verifyRollbackLater() {
} }
#endif #endif
#ifdef CONFIG_BT_ENABLED #ifdef CONFIG_BT_BLUEDROID_ENABLED
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
//overwritten in esp32-hal-bt.c //overwritten in esp32-hal-bt.c
bool btInUse() __attribute__((weak)); bool btInUse() __attribute__((weak));
@ -301,7 +305,7 @@ void initArduino() {
if (err) { if (err) {
log_e("Failed to initialize NVS! Error: %u", err); log_e("Failed to initialize NVS! Error: %u", err);
} }
#ifdef CONFIG_BT_ENABLED #if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED
if (!btInUse()) { if (!btInUse()) {
esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); esp_bt_controller_mem_release(ESP_BT_MODE_BTDM);
} }

View file

@ -206,7 +206,8 @@ bool rmtSetCarrier(int pin, bool carrier_en, bool carrier_level, uint32_t freque
log_w("GPIO %d - RMT Carrier must be a float percentage from 0 to 1. Setting to 50%.", pin); log_w("GPIO %d - RMT Carrier must be a float percentage from 0 to 1. Setting to 50%.", pin);
duty_percent = 0.5; duty_percent = 0.5;
} }
rmt_carrier_config_t carrier_cfg = {0}; rmt_carrier_config_t carrier_cfg;
memset((void *)&carrier_cfg, 0, sizeof(rmt_carrier_config_t));
carrier_cfg.duty_cycle = duty_percent; // duty cycle carrier_cfg.duty_cycle = duty_percent; // duty cycle
carrier_cfg.frequency_hz = carrier_en ? frequency_Hz : 0; // carrier frequency in Hz carrier_cfg.frequency_hz = carrier_en ? frequency_Hz : 0; // carrier frequency in Hz
carrier_cfg.flags.polarity_active_low = carrier_level; // carrier modulation polarity level carrier_cfg.flags.polarity_active_low = carrier_level; // carrier modulation polarity level
@ -313,7 +314,8 @@ static bool _rmtWrite(int pin, rmt_data_t *data, size_t num_rmt_symbols, bool bl
return false; return false;
} }
rmt_transmit_config_t transmit_cfg = {0}; // loop mode disabled rmt_transmit_config_t transmit_cfg; // loop mode disabled
memset((void *)&transmit_cfg, 0, sizeof(rmt_transmit_config_t));
bool retCode = true; bool retCode = true;
RMT_MUTEX_LOCK(bus); RMT_MUTEX_LOCK(bus);
@ -380,6 +382,7 @@ static bool _rmtRead(int pin, rmt_data_t *data, size_t *num_rmt_symbols, bool wa
// request reading RMT Channel Data // request reading RMT Channel Data
rmt_receive_config_t receive_config; rmt_receive_config_t receive_config;
memset((void *)&receive_config, 0, sizeof(rmt_receive_config_t));
receive_config.signal_range_min_ns = bus->signal_range_min_ns; receive_config.signal_range_min_ns = bus->signal_range_min_ns;
receive_config.signal_range_max_ns = bus->signal_range_max_ns; receive_config.signal_range_max_ns = bus->signal_range_max_ns;
@ -530,6 +533,7 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_
if (channel_direction == RMT_TX_MODE) { if (channel_direction == RMT_TX_MODE) {
// TX Channel // TX Channel
rmt_tx_channel_config_t tx_cfg; rmt_tx_channel_config_t tx_cfg;
memset((void *)&tx_cfg, 0, sizeof(rmt_tx_channel_config_t));
tx_cfg.gpio_num = pin; tx_cfg.gpio_num = pin;
// CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2 // CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2
tx_cfg.clk_src = RMT_CLK_SRC_DEFAULT; tx_cfg.clk_src = RMT_CLK_SRC_DEFAULT;
@ -559,6 +563,7 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_
} else { } else {
// RX Channel // RX Channel
rmt_rx_channel_config_t rx_cfg; rmt_rx_channel_config_t rx_cfg;
memset((void *)&rx_cfg, 0, sizeof(rmt_rx_channel_config_t));
rx_cfg.gpio_num = pin; rx_cfg.gpio_num = pin;
// CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2 // CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2
rx_cfg.clk_src = RMT_CLK_SRC_DEFAULT; rx_cfg.clk_src = RMT_CLK_SRC_DEFAULT;
@ -585,7 +590,8 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_
} }
// allocate memory for the RMT Copy encoder // allocate memory for the RMT Copy encoder
rmt_copy_encoder_config_t copy_encoder_config = {}; rmt_copy_encoder_config_t copy_encoder_config;
memset((void *)&copy_encoder_config, 0, sizeof(rmt_copy_encoder_config_t));
if (rmt_new_copy_encoder(&copy_encoder_config, &bus->rmt_copy_encoder_h) != ESP_OK) { if (rmt_new_copy_encoder(&copy_encoder_config, &bus->rmt_copy_encoder_h) != ESP_OK) {
log_e("GPIO %d - RMT Encoder Memory Allocation error.", pin); log_e("GPIO %d - RMT Encoder Memory Allocation error.", pin);
goto Err; goto Err;

View file

@ -74,6 +74,7 @@ struct spi_struct_t {
int8_t miso; int8_t miso;
int8_t mosi; int8_t mosi;
int8_t ss; int8_t ss;
bool ss_invert;
}; };
#if CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S2
@ -151,23 +152,23 @@ struct spi_struct_t {
// clang-format off // clang-format off
static spi_t _spi_bus_array[] = { static spi_t _spi_bus_array[] = {
#if CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S2
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2, -1, -1, -1, -1, false}
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 #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_SPI2_BASE), 0, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1, false}
#elif CONFIG_IDF_TARGET_ESP32C2 #elif CONFIG_IDF_TARGET_ESP32C2
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1, false}
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1, false}
#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 #elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
{(spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} {(spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1, false}
#else #else
{(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3, -1, -1, -1, -1, false}
#endif #endif
}; };
// clang-format on // clang-format on
@ -179,22 +180,22 @@ static spi_t _spi_bus_array[] = {
static spi_t _spi_bus_array[] = { static spi_t _spi_bus_array[] = {
#if CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S2
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2, -1, -1, -1, -1, false}
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 #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} {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1, false}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 1, -1, -1, -1, -1, false}
#elif CONFIG_IDF_TARGET_ESP32C2 #elif CONFIG_IDF_TARGET_ESP32C2
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1, false}
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1, false}
#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 #elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
{(spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} {(spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1, false}
#else #else
{(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2, -1, -1, -1, -1, false},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3, -1, -1, -1, -1} {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3, -1, -1, -1, -1, false}
#endif #endif
}; };
#endif #endif
@ -365,7 +366,7 @@ bool spiAttachSS(spi_t *spi, uint8_t ss_num, int8_t ss) {
return false; return false;
} }
pinMode(ss, OUTPUT); pinMode(ss, OUTPUT);
pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, ss_num), false, false); pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, ss_num), spi->ss_invert, false);
spiEnableSSPins(spi, (1 << ss_num)); spiEnableSSPins(spi, (1 << ss_num));
spi->ss = ss; spi->ss = ss;
if (!perimanSetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER_SS, (void *)(spi->num + 1), spi->num, -1)) { if (!perimanSetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER_SS, (void *)(spi->num + 1), spi->num, -1)) {
@ -435,6 +436,12 @@ void spiSSDisable(spi_t *spi) {
SPI_MUTEX_UNLOCK(); SPI_MUTEX_UNLOCK();
} }
void spiSSInvert(spi_t *spi, bool invert) {
if (spi) {
spi->ss_invert = invert;
}
}
void spiSSSet(spi_t *spi) { void spiSSSet(spi_t *spi) {
if (!spi) { if (!spi) {
return; return;

View file

@ -97,6 +97,8 @@ void spiSSSet(spi_t *spi);
void spiSSClear(spi_t *spi); void spiSSClear(spi_t *spi);
void spiWaitReady(spi_t *spi); void spiWaitReady(spi_t *spi);
//invert hardware SS
void spiSSInvert(spi_t *spi, bool invert);
uint32_t spiGetClockDiv(spi_t *spi); uint32_t spiGetClockDiv(spi_t *spi);
uint8_t spiGetDataMode(spi_t *spi); uint8_t spiGetDataMode(spi_t *spi);

View file

@ -616,7 +616,7 @@ void usb_persist_restart(restart_type_t mode) {
} }
static bool tinyusb_reserve_in_endpoint(uint8_t endpoint) { static bool tinyusb_reserve_in_endpoint(uint8_t endpoint) {
if (endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0) { if (endpoint > CFG_TUD_NUM_EPS || (tinyusb_endpoints.in & BIT(endpoint)) != 0) {
return false; return false;
} }
tinyusb_endpoints.in |= BIT(endpoint); tinyusb_endpoints.in |= BIT(endpoint);
@ -624,7 +624,7 @@ static bool tinyusb_reserve_in_endpoint(uint8_t endpoint) {
} }
static bool tinyusb_reserve_out_endpoint(uint8_t endpoint) { static bool tinyusb_reserve_out_endpoint(uint8_t endpoint) {
if (endpoint > 6 || (tinyusb_endpoints.out & BIT(endpoint)) != 0) { if (endpoint > CFG_TUD_NUM_EPS || (tinyusb_endpoints.out & BIT(endpoint)) != 0) {
return false; return false;
} }
tinyusb_endpoints.out |= BIT(endpoint); tinyusb_endpoints.out |= BIT(endpoint);
@ -632,11 +632,13 @@ static bool tinyusb_reserve_out_endpoint(uint8_t endpoint) {
} }
static bool tinyusb_has_available_fifos(void) { static bool tinyusb_has_available_fifos(void) {
uint8_t max_endpoints = 4, active_endpoints = 0; uint8_t max_endpoints = CFG_TUD_NUM_IN_EPS - 1, active_endpoints = 0;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
if (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) { if (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) {
max_endpoints = 5; //CDC endpoint 0x85 is actually not linked to FIFO and not used max_endpoints = CFG_TUD_NUM_IN_EPS; //CDC endpoint 0x85 is actually not linked to FIFO and not used
} }
for (uint8_t i = 1; i < 7; i++) { #endif
for (uint8_t i = 1; i <= CFG_TUD_NUM_EPS; i++) {
if ((tinyusb_endpoints.in & BIT(i)) != 0) { if ((tinyusb_endpoints.in & BIT(i)) != 0) {
active_endpoints++; active_endpoints++;
} }
@ -771,7 +773,7 @@ static void usb_device_task(void *param) {
* PUBLIC API * PUBLIC API
* */ * */
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"}; const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "CDC2", "MIDI", "CUSTOM"};
#endif #endif
static bool tinyusb_is_initialized = false; static bool tinyusb_is_initialized = false;
@ -862,7 +864,7 @@ uint8_t tinyusb_get_free_duplex_endpoint(void) {
log_e("No available IN endpoints"); log_e("No available IN endpoints");
return 0; return 0;
} }
for (uint8_t i = 1; i < 7; i++) { for (uint8_t i = 1; i <= CFG_TUD_NUM_IN_EPS; i++) {
if ((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) == 0) { if ((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) == 0) {
tinyusb_endpoints.in |= BIT(i); tinyusb_endpoints.in |= BIT(i);
tinyusb_endpoints.out |= BIT(i); tinyusb_endpoints.out |= BIT(i);
@ -878,13 +880,13 @@ uint8_t tinyusb_get_free_in_endpoint(void) {
log_e("No available IN endpoints"); log_e("No available IN endpoints");
return 0; return 0;
} }
for (uint8_t i = 1; i < 7; i++) { for (uint8_t i = 1; i <= CFG_TUD_NUM_IN_EPS; i++) {
if ((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) != 0) { if ((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) != 0) {
tinyusb_endpoints.in |= BIT(i); tinyusb_endpoints.in |= BIT(i);
return i; return i;
} }
} }
for (uint8_t i = 1; i < 7; i++) { for (uint8_t i = 1; i <= CFG_TUD_NUM_IN_EPS; i++) {
if ((tinyusb_endpoints.in & BIT(i)) == 0) { if ((tinyusb_endpoints.in & BIT(i)) == 0) {
tinyusb_endpoints.in |= BIT(i); tinyusb_endpoints.in |= BIT(i);
return i; return i;
@ -894,13 +896,13 @@ uint8_t tinyusb_get_free_in_endpoint(void) {
} }
uint8_t tinyusb_get_free_out_endpoint(void) { uint8_t tinyusb_get_free_out_endpoint(void) {
for (uint8_t i = 1; i < 7; i++) { for (uint8_t i = 1; i <= CFG_TUD_NUM_EPS; i++) {
if ((tinyusb_endpoints.out & BIT(i)) == 0 && (tinyusb_endpoints.in & BIT(i)) != 0) { if ((tinyusb_endpoints.out & BIT(i)) == 0 && (tinyusb_endpoints.in & BIT(i)) != 0) {
tinyusb_endpoints.out |= BIT(i); tinyusb_endpoints.out |= BIT(i);
return i; return i;
} }
} }
for (uint8_t i = 1; i < 7; i++) { for (uint8_t i = 1; i <= CFG_TUD_NUM_EPS; i++) {
if ((tinyusb_endpoints.out & BIT(i)) == 0) { if ((tinyusb_endpoints.out & BIT(i)) == 0) {
tinyusb_endpoints.out |= BIT(i); tinyusb_endpoints.out |= BIT(i);
return i; return i;

View file

@ -38,6 +38,13 @@ extern "C" {
#define CFG_TUD_ENDOINT_SIZE 64 #define CFG_TUD_ENDOINT_SIZE 64
#endif #endif
#endif #endif
#if CONFIG_IDF_TARGET_ESP32P4
#define CFG_TUD_NUM_EPS 15
#define CFG_TUD_NUM_IN_EPS 8
#else
#define CFG_TUD_NUM_EPS 6
#define CFG_TUD_NUM_IN_EPS 5
#endif
typedef struct { typedef struct {
uint16_t vid; uint16_t vid;
@ -88,6 +95,7 @@ typedef enum {
USB_INTERFACE_HID, USB_INTERFACE_HID,
USB_INTERFACE_VENDOR, USB_INTERFACE_VENDOR,
USB_INTERFACE_CDC, USB_INTERFACE_CDC,
USB_INTERFACE_CDC2,
USB_INTERFACE_MIDI, USB_INTERFACE_MIDI,
USB_INTERFACE_CUSTOM, USB_INTERFACE_CUSTOM,
USB_INTERFACE_MAX USB_INTERFACE_MAX

View file

@ -1,4 +1,4 @@
// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD // Copyright 2015-2025 Espressif Systems (Shanghai) PTE LTD
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -33,6 +33,11 @@
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "driver/rtc_io.h"
#include "driver/lp_io.h"
#include "soc/uart_periph.h"
#include "esp_private/uart_share_hw_ctrl.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 #define REF_TICK_BAUDRATE_LIMIT 250000 // this is maximum UART badrate using REF_TICK as clock
@ -53,6 +58,7 @@ struct uart_struct_t {
uint16_t _rx_buffer_size, _tx_buffer_size; // UART RX and TX buffer sizes uint16_t _rx_buffer_size, _tx_buffer_size; // UART RX and TX buffer sizes
bool _inverted; // UART inverted signal bool _inverted; // UART inverted signal
uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold
int8_t _uart_clock_source; // UART Clock Source used when it is started using uartBegin()
}; };
#if CONFIG_DISABLE_HAL_LOCKS #if CONFIG_DISABLE_HAL_LOCKS
@ -61,18 +67,21 @@ struct uart_struct_t {
#define UART_MUTEX_UNLOCK() #define UART_MUTEX_UNLOCK()
static uart_t _uart_bus_array[] = { static uart_t _uart_bus_array[] = {
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#if SOC_UART_HP_NUM > 1 #if SOC_UART_NUM > 1
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif #endif
#if SOC_UART_HP_NUM > 2 #if SOC_UART_NUM > 2
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif #endif
#if SOC_UART_HP_NUM > 3 #if SOC_UART_NUM > 3
{3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif #endif
#if SOC_UART_HP_NUM > 4 #if SOC_UART_NUM > 4
{4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif
#if SOC_UART_NUM > 5
{5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif #endif
}; };
@ -87,28 +96,122 @@ static uart_t _uart_bus_array[] = {
xSemaphoreGive(uart->lock) xSemaphoreGive(uart->lock)
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}, {NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#if SOC_UART_HP_NUM > 1 #if SOC_UART_NUM > 1
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif #endif
#if SOC_UART_HP_NUM > 2 #if SOC_UART_NUM > 2
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif #endif
#if SOC_UART_HP_NUM > 3 #if SOC_UART_NUM > 3
{NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif #endif
#if SOC_UART_HP_NUM > 4 #if SOC_UART_NUM > 4
{NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, {NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif
#if SOC_UART_NUM > 5
{NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
#endif #endif
}; };
#endif #endif
#if SOC_UART_LP_NUM >= 1
// LP UART enable pins routine
static bool lp_uart_config_io(uint8_t uart_num, int8_t pin, rtc_gpio_mode_t direction, uint32_t idx) {
/* Skip configuration if the LP_IO is -1 */
if (pin < 0) {
return true;
}
// Initialize LP_IO
if (rtc_gpio_init(pin) != ESP_OK) {
log_e("Failed to initialize LP_IO %d", pin);
return false;
}
// Set LP_IO direction
if (rtc_gpio_set_direction(pin, direction) != ESP_OK) {
log_e("Failed to set LP_IO %d direction", pin);
return false;
}
// Connect pins
const uart_periph_sig_t *upin = &uart_periph_signal[uart_num].pins[idx];
#if !SOC_LP_GPIO_MATRIX_SUPPORTED // ESP32-C6/C61/C5
// When LP_IO Matrix is not support, LP_IO Mux must be connected to the pins
if (rtc_gpio_iomux_func_sel(pin, upin->iomux_func) != ESP_OK) {
log_e("Failed to set LP_IO pin %d into Mux function", pin);
return false;
}
#else // So far, only ESP32-P4
// If the configured pin is the default LP_IO Mux pin for LP UART, then set the LP_IO MUX function
if (upin->default_gpio == pin) {
if (rtc_gpio_iomux_func_sel(pin, upin->iomux_func) != ESP_OK) {
log_e("Failed to set LP_IO pin %d into Mux function", pin);
return false;
}
} else {
// Otherwise, set the LP_IO Matrix and select FUNC1
if (rtc_gpio_iomux_func_sel(pin, 1) != ESP_OK) {
log_e("Failed to set LP_IO pin %d into Mux function GPIO", pin);
return false;
}
// Connect the LP_IO to the LP UART peripheral signal
esp_err_t ret;
if (direction == RTC_GPIO_MODE_OUTPUT_ONLY) {
ret = lp_gpio_connect_out_signal(pin, UART_PERIPH_SIGNAL(uart_num, idx), 0, 0);
} else {
ret = lp_gpio_connect_in_signal(pin, UART_PERIPH_SIGNAL(uart_num, idx), 0);
}
if (ret != ESP_OK) {
log_e("Failed to connect LP_IO pin %d to UART%d signal", pin, uart_num);
return false;
}
}
#endif // SOC_LP_GPIO_MATRIX_SUPPORTED
return true;
}
// When LP UART needs the RTC IO MUX to set the pin, it will always have fixed pins for RX, TX, CTS and RTS
static bool lpuartCheckPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin, uint8_t uart_nr) {
// check if LP UART is being used and if the pins are valid
#if !SOC_LP_GPIO_MATRIX_SUPPORTED // ESP32-C6/C61/C5
uint16_t lp_uart_fixed_pin = uart_periph_signal[uart_nr].pins[SOC_UART_RX_PIN_IDX].default_gpio;
if (uart_nr >= SOC_UART_HP_NUM) { // it is a LP UART NUM
if (rxPin > 0 && rxPin != lp_uart_fixed_pin) {
log_e("UART%d LP UART requires RX pin to be set to %d.", uart_nr, lp_uart_fixed_pin);
return false;
}
lp_uart_fixed_pin = uart_periph_signal[uart_nr].pins[SOC_UART_TX_PIN_IDX].default_gpio;
if (txPin > 0 && txPin != lp_uart_fixed_pin) {
log_e("UART%d LP UART requires TX pin to be set to %d.", uart_nr, lp_uart_fixed_pin);
return false;
}
lp_uart_fixed_pin = uart_periph_signal[uart_nr].pins[SOC_UART_CTS_PIN_IDX].default_gpio;
if (ctsPin > 0 && ctsPin != lp_uart_fixed_pin) {
log_e("UART%d LP UART requires CTS pin to be set to %d.", uart_nr, lp_uart_fixed_pin);
return false;
}
lp_uart_fixed_pin = uart_periph_signal[uart_nr].pins[SOC_UART_RTS_PIN_IDX].default_gpio;
if (rtsPin > 0 && rtsPin != lp_uart_fixed_pin) {
log_e("UART%d LP UART requires RTS pin to be set to %d.", uart_nr, lp_uart_fixed_pin);
return false;
}
}
return true;
#else // ESP32-P4 can set any pin for LP UART
return true;
#endif // SOC_LP_GPIO_MATRIX_SUPPORTED
}
#endif // SOC_UART_LP_NUM >= 1
// Negative Pin Number will keep it unmodified, thus this function can detach individual pins // 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 // 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) { static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) {
if (uart_num >= SOC_UART_HP_NUM) { if (uart_num >= SOC_UART_NUM) {
log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
return false; return false;
} }
// get UART information // get UART information
@ -117,7 +220,7 @@ static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
//log_v("detaching UART%d pins: prev,pin RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, //log_v("detaching UART%d pins: prev,pin RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num,
// uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10);
// detaches pins and sets Peripheral Manager and UART information // detaches HP and LP pins and sets Peripheral Manager and UART information
if (rxPin >= 0 && uart->_rxPin == rxPin && perimanGetPinBusType(rxPin) == ESP32_BUS_TYPE_UART_RX) { if (rxPin >= 0 && uart->_rxPin == rxPin && perimanGetPinBusType(rxPin) == ESP32_BUS_TYPE_UART_RX) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxPin], PIN_FUNC_GPIO); gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxPin], PIN_FUNC_GPIO);
// avoids causing BREAK in the UART line // avoids causing BREAK in the UART line
@ -194,8 +297,8 @@ static bool _uartDetachBus_RTS(void *busptr) {
// Attach function for UART // Attach function for UART
// connects the IO Pad, set Paripheral Manager and internal UART structure data // 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) { static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) {
if (uart_num >= SOC_UART_HP_NUM) { if (uart_num >= SOC_UART_NUM) {
log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
return false; return false;
} }
// get UART information // get UART information
@ -203,6 +306,8 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
//log_v("attaching UART%d pins: prev,new RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, //log_v("attaching UART%d pins: prev,new RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num,
// uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10);
// IDF uart_set_pin() checks if the pin is used within LP UART and if it is a valid RTC IO pin
// No need for Arduino Layer to check it again
bool retCode = true; bool retCode = true;
if (rxPin >= 0) { if (rxPin >= 0) {
// forces a clean detaching from a previous peripheral // forces a clean detaching from a previous peripheral
@ -211,6 +316,11 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
} }
// connect RX Pad // connect RX Pad
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
#if SOC_UART_LP_NUM >= 1
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
ret &= lp_uart_config_io(uart->num, rxPin, RTC_GPIO_MODE_INPUT_ONLY, SOC_UART_RX_PIN_IDX);
}
#endif
if (ret) { if (ret) {
ret &= perimanSetPinBus(rxPin, ESP32_BUS_TYPE_UART_RX, (void *)uart, uart_num, -1); ret &= perimanSetPinBus(rxPin, ESP32_BUS_TYPE_UART_RX, (void *)uart, uart_num, -1);
if (ret) { if (ret) {
@ -229,6 +339,11 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
} }
// connect TX Pad // connect TX Pad
bool ret = ESP_OK == uart_set_pin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); bool ret = ESP_OK == uart_set_pin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
#if SOC_UART_LP_NUM >= 1
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
ret &= lp_uart_config_io(uart->num, txPin, RTC_GPIO_MODE_OUTPUT_ONLY, SOC_UART_TX_PIN_IDX);
}
#endif
if (ret) { if (ret) {
ret &= perimanSetPinBus(txPin, ESP32_BUS_TYPE_UART_TX, (void *)uart, uart_num, -1); ret &= perimanSetPinBus(txPin, ESP32_BUS_TYPE_UART_TX, (void *)uart, uart_num, -1);
if (ret) { if (ret) {
@ -247,6 +362,11 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
} }
// connect CTS Pad // connect CTS Pad
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin); bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin);
#if SOC_UART_LP_NUM >= 1
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
ret &= lp_uart_config_io(uart->num, ctsPin, RTC_GPIO_MODE_INPUT_ONLY, SOC_UART_CTS_PIN_IDX);
}
#endif
if (ret) { if (ret) {
ret &= perimanSetPinBus(ctsPin, ESP32_BUS_TYPE_UART_CTS, (void *)uart, uart_num, -1); ret &= perimanSetPinBus(ctsPin, ESP32_BUS_TYPE_UART_CTS, (void *)uart, uart_num, -1);
if (ret) { if (ret) {
@ -265,6 +385,11 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
} }
// connect RTS Pad // connect RTS Pad
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE); bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE);
#if SOC_UART_LP_NUM >= 1
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
ret &= lp_uart_config_io(uart->num, rtsPin, RTC_GPIO_MODE_OUTPUT_ONLY, SOC_UART_RTS_PIN_IDX);
}
#endif
if (ret) { if (ret) {
ret &= perimanSetPinBus(rtsPin, ESP32_BUS_TYPE_UART_RTS, (void *)uart, uart_num, -1); ret &= perimanSetPinBus(rtsPin, ESP32_BUS_TYPE_UART_RTS, (void *)uart, uart_num, -1);
if (ret) { if (ret) {
@ -321,13 +446,20 @@ bool uartIsDriverInstalled(uart_t *uart) {
// Negative Pin Number will keep it unmodified, thus this function can set individual pins // Negative Pin Number will keep it unmodified, thus this function can set individual pins
// When pins are changed, it will detach the previous one // 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) { bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) {
if (uart_num >= SOC_UART_HP_NUM) { if (uart_num >= SOC_UART_NUM) {
log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
return false; return false;
} }
// get UART information // get UART information
uart_t *uart = &_uart_bus_array[uart_num]; uart_t *uart = &_uart_bus_array[uart_num];
#if SOC_UART_LP_NUM >= 1
// check if LP UART is being used and if the pins are valid
if (!lpuartCheckPins(rxPin, txPin, ctsPin, rtsPin, uart_num)) {
return false; // failed to set pins
}
#endif
bool retCode = true; bool retCode = true;
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
@ -391,7 +523,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 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 uint8_t rxfifo_full_thrhd
) { ) {
if (uart_nr >= SOC_UART_HP_NUM) { if (uart_nr >= SOC_UART_NUM) {
return false; // no new driver has to be installed return false; // no new driver has to be installed
} }
uart_t *uart = &_uart_bus_array[uart_nr]; uart_t *uart = &_uart_bus_array[uart_nr];
@ -413,13 +545,24 @@ 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 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 uint8_t rxfifo_full_thrhd
) { ) {
if (uart_nr >= SOC_UART_HP_NUM) { if (uart_nr >= SOC_UART_NUM) {
log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
return NULL; // no new driver was installed return NULL; // no new driver was installed
} }
uart_t *uart = &_uart_bus_array[uart_nr]; uart_t *uart = &_uart_bus_array[uart_nr];
log_v("UART%d baud(%ld) Mode(%x) rxPin(%d) txPin(%d)", uart_nr, baudrate, config, rxPin, txPin); log_v("UART%d baud(%ld) Mode(%x) rxPin(%d) txPin(%d)", uart_nr, baudrate, config, rxPin, txPin);
#if SOC_UART_LP_NUM >= 1
// check if LP UART is being used and if the pins are valid
if (!lpuartCheckPins(rxPin, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, uart_nr)) {
if (uart_is_driver_installed(uart_nr)) {
return uart; // keep the same installed driver
} else {
return NULL; // no new driver was installed
}
}
#endif
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
if (uart->lock == NULL) { if (uart->lock == NULL) {
uart->lock = xSemaphoreCreateMutex(); uart->lock = xSemaphoreCreateMutex();
@ -436,20 +579,18 @@ uart_t *uartBegin(
if (uart->_rx_buffer_size != rx_buffer_size || uart->_tx_buffer_size != tx_buffer_size || uart->_inverted != inverted if (uart->_rx_buffer_size != rx_buffer_size || uart->_tx_buffer_size != tx_buffer_size || uart->_inverted != inverted
|| uart->_rxfifo_full_thrhd != rxfifo_full_thrhd) { || uart->_rxfifo_full_thrhd != rxfifo_full_thrhd) {
log_v("UART%d changing buffer sizes or inverted signal or rxfifo_full_thrhd. IDF driver will be restarted", uart_nr); log_v("UART%d changing buffer sizes or inverted signal or rxfifo_full_thrhd. IDF driver will be restarted", uart_nr);
log_v("RX buffer size: %d -> %d", uart->_rx_buffer_size, rx_buffer_size);
log_v("TX buffer size: %d -> %d", uart->_tx_buffer_size, tx_buffer_size);
log_v("Inverted signal: %s -> %s", uart->_inverted ? "true" : "false", inverted ? "true" : "false");
log_v("RX FIFO full threshold: %d -> %d", uart->_rxfifo_full_thrhd, rxfifo_full_thrhd);
uartEnd(uart_nr); uartEnd(uart_nr);
} else { } else {
bool retCode = true; bool retCode = true;
UART_MUTEX_LOCK();
//User may just want to change some parameters, such as baudrate, data length, parity, stop bits or pins //User may just want to change some parameters, such as baudrate, data length, parity, stop bits or pins
if (uart->_baudrate != baudrate) { if (uart->_baudrate != baudrate) {
if (ESP_OK != uart_set_baudrate(uart_nr, baudrate)) { retCode = uartSetBaudRate(uart, baudrate);
log_e("UART%d changing baudrate failed.", uart_nr);
retCode = false;
} else {
log_v("UART%d changed baudrate to %d", uart_nr, baudrate);
uart->_baudrate = baudrate;
}
} }
UART_MUTEX_LOCK();
uart_word_length_t data_bits = (config & 0xc) >> 2; uart_word_length_t data_bits = (config & 0xc) >> 2;
uart_parity_t parity = config & 0x3; uart_parity_t parity = config & 0x3;
uart_stop_bits_t stop_bits = (config & 0x30) >> 4; uart_stop_bits_t stop_bits = (config & 0x30) >> 4;
@ -500,7 +641,7 @@ uart_t *uartBegin(
} }
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
if (retCode) { if (retCode) {
// UART driver was already working, just return the uart_t structure, syaing that no new driver was installed // UART driver was already working, just return the uart_t structure, saying that no new driver was installed
return uart; return uart;
} }
// if we reach this point, it means that we need to restart the UART driver // if we reach this point, it means that we need to restart the UART driver
@ -516,22 +657,49 @@ uart_t *uartBegin(
uart_config.parity = (config & 0x3); uart_config.parity = (config & 0x3);
uart_config.stop_bits = (config & 0x30) >> 4; uart_config.stop_bits = (config & 0x30) >> 4;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.rx_flow_ctrl_thresh = rxfifo_full_thrhd; uart_config.rx_flow_ctrl_thresh = rxfifo_full_thrhd >= UART_HW_FIFO_LEN(uart_nr) ? UART_HW_FIFO_LEN(uart_nr) - 6 : rxfifo_full_thrhd;
log_v(
"UART%d RX FIFO full threshold set to %d (value requested: %d || FIFO Max = %d)", uart_nr, uart_config.rx_flow_ctrl_thresh, rxfifo_full_thrhd,
UART_HW_FIFO_LEN(uart_nr)
);
rxfifo_full_thrhd = uart_config.rx_flow_ctrl_thresh; // makes sure that it will be set correctly in the struct
uart_config.baud_rate = baudrate; uart_config.baud_rate = baudrate;
// there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored #if SOC_UART_LP_NUM >= 1
// therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue. if (uart_nr >= SOC_UART_HP_NUM) { // it is a LP UART NUM
if (uart->_uart_clock_source > 0) {
uart_config.lp_source_clk = (soc_periph_lp_uart_clk_src_t)uart->_uart_clock_source; // use user defined LP UART clock
log_v("Setting UART%d to user defined LP clock source (%d) ", uart_nr, uart->_uart_clock_source);
} else {
uart_config.lp_source_clk = LP_UART_SCLK_DEFAULT; // use default LP clock
log_v("Setting UART%d to Default LP clock source", uart_nr);
}
} else
#endif // SOC_UART_LP_NUM >= 1
{
if (uart->_uart_clock_source >= 0) {
uart_config.source_clk = (soc_module_clk_t)uart->_uart_clock_source; // use user defined HP UART clock
log_v("Setting UART%d to user defined HP clock source (%d) ", uart_nr, uart->_uart_clock_source);
} else {
// there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored
// therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue.
#if SOC_UART_SUPPORT_XTAL_CLK #if SOC_UART_SUPPORT_XTAL_CLK
uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4 uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4
log_v("Setting UART%d to use XTAL clock", uart_nr);
#elif SOC_UART_SUPPORT_REF_TICK #elif SOC_UART_SUPPORT_REF_TICK
if (baudrate <= REF_TICK_BAUDRATE_LIMIT) { 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 uart_config.source_clk = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
} else { log_v("Setting UART%d to use REF_TICK clock", uart_nr);
uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency! } else {
} uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency!
log_v("Setting UART%d to use APB clock", uart_nr);
}
#else #else
// Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6 // Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6|P4
uart_config.source_clk = UART_SCLK_DEFAULT; // baudrate may change with the APB Frequency! uart_config.source_clk = UART_SCLK_DEFAULT; // baudrate may change with the APB Frequency!
#endif log_v("Setting UART%d to use DEFAULT clock", uart_nr);
#endif // SOC_UART_SUPPORT_XTAL_CLK
}
}
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
bool retCode = ESP_OK == uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0); bool retCode = ESP_OK == uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0);
@ -559,6 +727,14 @@ uart_t *uartBegin(
uart->_tx_buffer_size = tx_buffer_size; uart->_tx_buffer_size = tx_buffer_size;
uart->has_peek = false; uart->has_peek = false;
uart->peek_byte = 0; uart->peek_byte = 0;
#if SOC_UART_LP_NUM >= 1
if (uart_nr >= SOC_UART_HP_NUM) {
uart->_uart_clock_source = uart_config.lp_source_clk;
} else
#endif
{
uart->_uart_clock_source = uart_config.source_clk;
}
} }
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
@ -600,7 +776,11 @@ bool uartSetRxTimeout(uart_t *uart, uint8_t numSymbTimeout) {
if (uart == NULL) { if (uart == NULL) {
return false; return false;
} }
uint16_t maxRXTimeout = uart_get_max_rx_timeout(uart->num);
if (numSymbTimeout > maxRXTimeout) {
log_e("Invalid RX Timeout value, its limit is %d", maxRXTimeout);
return false;
}
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
bool retCode = (ESP_OK == uart_set_rx_timeout(uart->num, numSymbTimeout)); bool retCode = (ESP_OK == uart_set_rx_timeout(uart->num, numSymbTimeout));
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
@ -611,16 +791,25 @@ bool uartSetRxFIFOFull(uart_t *uart, uint8_t numBytesFIFOFull) {
if (uart == NULL) { if (uart == NULL) {
return false; return false;
} }
uint8_t rxfifo_full_thrhd = numBytesFIFOFull >= UART_HW_FIFO_LEN(uart->num) ? UART_HW_FIFO_LEN(uart->num) - 6 : numBytesFIFOFull;
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
bool retCode = (ESP_OK == uart_set_rx_full_threshold(uart->num, numBytesFIFOFull)); bool retCode = (ESP_OK == uart_set_rx_full_threshold(uart->num, rxfifo_full_thrhd));
if (retCode) {
uart->_rxfifo_full_thrhd = rxfifo_full_thrhd;
if (rxfifo_full_thrhd != numBytesFIFOFull) {
log_w("The RX FIFO Full value for UART%d was set to %d instead of %d", uart->num, rxfifo_full_thrhd, numBytesFIFOFull);
}
log_v("UART%d RX FIFO Full value set to %d from a requested value of %d", uart->num, rxfifo_full_thrhd, numBytesFIFOFull);
} else {
log_e("UART%d failed to set RX FIFO Full value to %d", uart->num, numBytesFIFOFull);
}
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
return retCode; return retCode;
} }
void uartEnd(uint8_t uart_num) { void uartEnd(uint8_t uart_num) {
if (uart_num >= SOC_UART_HP_NUM) { if (uart_num >= SOC_UART_NUM) {
log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1); log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
return; return;
} }
// get UART information // get UART information
@ -645,7 +834,7 @@ void uartSetRxInvert(uart_t *uart, bool invert) {
// ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV)); // ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
// else // else
// ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE)); // ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE));
log_e("uartSetRxInvert is not supported in ESP32C6, ESP32H2 and ESP32P4");
#else #else
// this implementation is better over IDF API because it only affects RXD // this implementation is better over IDF API because it only affects RXD
// this is supported in ESP32, ESP32-S2 and ESP32-C3 // this is supported in ESP32, ESP32-S2 and ESP32-C3
@ -800,21 +989,66 @@ void uartFlushTxOnly(uart_t *uart, bool txOnly) {
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
} }
void uartSetBaudRate(uart_t *uart, uint32_t baud_rate) { bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate) {
if (uart == NULL) { if (uart == NULL) {
return; return false;
}
bool retCode = true;
soc_module_clk_t newClkSrc = UART_SCLK_DEFAULT;
int8_t previousClkSrc = uart->_uart_clock_source;
#if SOC_UART_LP_NUM >= 1
if (uart->num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
if (uart->_uart_clock_source > 0) {
newClkSrc = (soc_periph_lp_uart_clk_src_t)uart->_uart_clock_source; // use user defined LP UART clock
log_v("Setting UART%d to user defined LP clock source (%d) ", uart->num, newClkSrc);
} else {
newClkSrc = LP_UART_SCLK_DEFAULT; // use default LP clock
log_v("Setting UART%d to Default LP clock source", uart->num);
}
} else
#endif // SOC_UART_LP_NUM >= 1
{
if (uart->_uart_clock_source >= 0) {
newClkSrc = (soc_module_clk_t)uart->_uart_clock_source; // use user defined HP UART clock
log_v("Setting UART%d to use HP clock source (%d) ", uart->num, newClkSrc);
} else {
// there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored
// therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue.
#if SOC_UART_SUPPORT_XTAL_CLK
newClkSrc = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4
log_v("Setting UART%d to use XTAL clock", uart->num);
#elif SOC_UART_SUPPORT_REF_TICK
if (baud_rate <= REF_TICK_BAUDRATE_LIMIT) {
newClkSrc = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
log_v("Setting UART%d to use REF_TICK clock", uart->num);
} else {
newClkSrc = UART_SCLK_APB; // baudrate may change with the APB Frequency!
log_v("Setting UART%d to use APB clock", uart->num);
}
#else
// Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6|P4
// using newClkSrc = UART_SCLK_DEFAULT as defined in the variable declaration
log_v("Setting UART%d to use DEFAULT clock", uart->num);
#endif // SOC_UART_SUPPORT_XTAL_CLK
}
} }
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
#if !SOC_UART_SUPPORT_XTAL_CLK // if necessary, set the correct UART Clock Source before changing the baudrate
soc_module_clk_t newClkSrc = baud_rate <= REF_TICK_BAUDRATE_LIMIT ? SOC_MOD_CLK_REF_TICK : SOC_MOD_CLK_APB; if (previousClkSrc < 0 || previousClkSrc != newClkSrc) {
uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc); HP_UART_SRC_CLK_ATOMIC() {
#endif uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc);
}
uart->_uart_clock_source = newClkSrc;
}
if (uart_set_baudrate(uart->num, baud_rate) == ESP_OK) { if (uart_set_baudrate(uart->num, baud_rate) == ESP_OK) {
log_v("Setting UART%d baud rate to %ld.", uart->num, baud_rate);
uart->_baudrate = baud_rate; uart->_baudrate = baud_rate;
} else { } else {
log_e("Setting UART%d baud rate to %d has failed.", uart->num, baud_rate); retCode = false;
log_e("Setting UART%d baud rate to %ld has failed.", uart->num, baud_rate);
} }
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
return retCode;
} }
uint32_t uartGetBaudRate(uart_t *uart) { uint32_t uartGetBaudRate(uart_t *uart) {
@ -889,7 +1123,7 @@ void uart_install_putc() {
// Routines that take care of UART mode in the HardwareSerial Class code // 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 // used to set UART_MODE_RS485_HALF_DUPLEX auto RTS for TXD for ESP32 chips
bool uartSetMode(uart_t *uart, uart_mode_t mode) { bool uartSetMode(uart_t *uart, uart_mode_t mode) {
if (uart == NULL || uart->num >= SOC_UART_HP_NUM) { if (uart == NULL || uart->num >= SOC_UART_NUM) {
return false; return false;
} }
@ -899,7 +1133,33 @@ bool uartSetMode(uart_t *uart, uart_mode_t mode) {
return retCode; return retCode;
} }
// this function will set the uart clock source
// it must be called before uartBegin(), otherwise it won't change any thing.
bool uartSetClockSource(uint8_t uartNum, uart_sclk_t clkSrc) {
if (uartNum >= SOC_UART_NUM) {
log_e("UART%d is invalid. This device has %d UARTs, from 0 to %d.", uartNum, SOC_UART_NUM, SOC_UART_NUM - 1);
return false;
}
uart_t *uart = &_uart_bus_array[uartNum];
#if SOC_UART_LP_NUM >= 1
if (uart->num >= SOC_UART_HP_NUM) {
switch (clkSrc) {
case UART_SCLK_XTAL: uart->_uart_clock_source = LP_UART_SCLK_XTAL_D2; break;
case UART_SCLK_RTC: uart->_uart_clock_source = LP_UART_SCLK_LP_FAST; break;
case UART_SCLK_DEFAULT:
default: uart->_uart_clock_source = LP_UART_SCLK_DEFAULT;
}
} else
#endif
{
uart->_uart_clock_source = clkSrc;
}
//log_i("UART%d set clock source to %d", uart->num, uart->_uart_clock_source);
return true;
}
void uartSetDebug(uart_t *uart) { void uartSetDebug(uart_t *uart) {
// LP UART is not supported for debug
if (uart == NULL || uart->num >= SOC_UART_HP_NUM) { if (uart == NULL || uart->num >= SOC_UART_HP_NUM) {
s_uart_debug_nr = -1; s_uart_debug_nr = -1;
} else { } else {
@ -926,7 +1186,7 @@ int log_printfv(const char *format, va_list arg) {
return 0; return 0;
} }
} }
/* /*
// This causes dead locks with logging in specific cases and also with C++ constructors that may send logs // This causes dead locks with logging in specific cases and also with C++ constructors that may send logs
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
@ -934,16 +1194,8 @@ int log_printfv(const char *format, va_list arg) {
} }
#endif #endif
*/ */
#if (ARDUINO_USB_CDC_ON_BOOT == 1 && ARDUINO_USB_MODE == 0) || CONFIG_IDF_TARGET_ESP32C3 \
|| ((CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4) && ARDUINO_USB_CDC_ON_BOOT == 1)
vsnprintf(temp, len + 1, format, arg); vsnprintf(temp, len + 1, format, arg);
ets_printf("%s", temp); ets_printf("%s", temp);
#else
int wlen = vsnprintf(temp, len + 1, format, arg);
for (int i = 0; i < wlen; i++) {
ets_write_char_uart(temp[i]);
}
#endif
/* /*
// This causes dead locks with logging and also with constructors that may send logs // This causes dead locks with logging and also with constructors that may send logs
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
@ -1170,7 +1422,9 @@ unsigned long uartDetectBaudrate(uart_t *uart) {
This creates a loop that lets us receive anything we send on the UART without external wires. 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) { void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) {
if (uartNum > SOC_UART_HP_NUM - 1 || !GPIO_IS_VALID_GPIO(rxPin)) { // LP UART is not supported for loopback
if (uartNum >= SOC_UART_HP_NUM || !GPIO_IS_VALID_GPIO(rxPin)) {
log_e("UART%d is not supported for loopback or RX pin %d is invalid.", uartNum, rxPin);
return; return;
} }
esp_rom_gpio_connect_out_signal(rxPin, UART_TX_SIGNAL(uartNum), false, false); esp_rom_gpio_connect_out_signal(rxPin, UART_TX_SIGNAL(uartNum), false, false);
@ -1198,4 +1452,24 @@ int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize) {
return uart_write_bytes_with_break(uartNum, (const void *)msg, msgSize, 12); return uart_write_bytes_with_break(uartNum, (const void *)msg, msgSize, 12);
} }
// returns the maximum valid uart RX Timeout based on the UART Source Clock and Baudrate
uint16_t uart_get_max_rx_timeout(uint8_t uartNum) {
if (uartNum >= SOC_UART_NUM) {
log_e("UART%d is invalid. This device has %d UARTs, from 0 to %d.", uartNum, SOC_UART_NUM, SOC_UART_NUM - 1);
return (uint16_t)-1;
}
uint16_t tout_max_thresh = uart_ll_max_tout_thrd(UART_LL_GET_HW(uartNum));
uint8_t symbol_len = 1; // number of bits per symbol including start
uart_parity_t parity_mode;
uart_stop_bits_t stop_bit;
uart_word_length_t data_bit;
uart_ll_get_data_bit_num(UART_LL_GET_HW(uartNum), &data_bit);
uart_ll_get_stop_bits(UART_LL_GET_HW(uartNum), &stop_bit);
uart_ll_get_parity(UART_LL_GET_HW(uartNum), &parity_mode);
symbol_len += (data_bit < UART_DATA_BITS_MAX) ? (uint8_t)data_bit + 5 : 8;
symbol_len += (stop_bit > UART_STOP_BITS_1) ? 2 : 1;
symbol_len += (parity_mode > UART_PARITY_DISABLE) ? 1 : 0;
return (uint16_t)(tout_max_thresh / symbol_len);
}
#endif /* SOC_UART_SUPPORTED */ #endif /* SOC_UART_SUPPORTED */

View file

@ -1,4 +1,4 @@
// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD // Copyright 2015-2025 Espressif Systems (Shanghai) PTE LTD
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#if SOC_UART_SUPPORTED #if SOC_UART_SUPPORTED
#include "soc/uart_pins.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -57,7 +58,7 @@ void uartWriteBuf(uart_t *uart, const uint8_t *data, size_t len);
void uartFlush(uart_t *uart); void uartFlush(uart_t *uart);
void uartFlushTxOnly(uart_t *uart, bool txOnly); void uartFlushTxOnly(uart_t *uart, bool txOnly);
void uartSetBaudRate(uart_t *uart, uint32_t baud_rate); bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate);
uint32_t uartGetBaudRate(uart_t *uart); uint32_t uartGetBaudRate(uart_t *uart);
void uartSetRxInvert(uart_t *uart, bool invert); void uartSetRxInvert(uart_t *uart, bool invert);
@ -96,6 +97,19 @@ bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t thr
// UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes) // UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes)
bool uartSetMode(uart_t *uart, uart_mode_t mode); bool uartSetMode(uart_t *uart, uart_mode_t mode);
// Used to set the UART clock source mode. It must be set before calling uartBegin(), otherwise it won't have any effect.
// Not all clock source are available to every SoC. The compatible option are listed here:
// UART_SCLK_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source
// UART_SCLK_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3
// UART_SCLK_PLL_F80M :: ESP32-C5, ESP32-C6, ESP32-C61 and ESP32-P4
// UART_SCLK_PLL_F40M :: ESP32-C2
// UART_SCLK_PLL_F48M :: ESP32-H2
// UART_SCLK_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
// UART_SCLK_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
// UART_SCLK_REF_TICK :: ESP32 and ESP32-S2
// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only LP_UART_SCLK_LP_FAST (RTC_FAST) or LP_UART_SCLK_XTAL_D2 (XTAL/2) as Clock Source
bool uartSetClockSource(uint8_t uartNum, uart_sclk_t clkSrc);
void uartStartDetectBaudrate(uart_t *uart); void uartStartDetectBaudrate(uart_t *uart);
unsigned long uartDetectBaudrate(uart_t *uart); unsigned long uartDetectBaudrate(uart_t *uart);
@ -115,6 +129,10 @@ void uart_send_break(uint8_t uartNum);
// Sends a buffer and at the end of the stream, it generates BREAK in the line // Sends a buffer and at the end of the stream, it generates BREAK in the line
int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize); int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize);
// UART RX Timeout (in UART Symbols) depends on the UART Clock Source and the SoC that is used
// This is a helper function that calculates what is the maximum RX Timeout that a running UART IDF driver allows.
uint16_t uart_get_max_rx_timeout(uint8_t uartNum);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -121,11 +121,11 @@ void feedLoopWDT();
//enable/disable WDT for the IDLE task on Core 0 (SYSTEM) //enable/disable WDT for the IDLE task on Core 0 (SYSTEM)
void enableCore0WDT(); void enableCore0WDT();
void disableCore0WDT(); bool disableCore0WDT();
#ifndef CONFIG_FREERTOS_UNICORE #ifndef CONFIG_FREERTOS_UNICORE
//enable/disable WDT for the IDLE task on Core 1 (Arduino) //enable/disable WDT for the IDLE task on Core 1 (Arduino)
void enableCore1WDT(); void enableCore1WDT();
void disableCore1WDT(); bool disableCore1WDT();
#endif #endif
//if xCoreID < 0 or CPU is unicore, it will use xTaskCreate, else xTaskCreatePinnedToCore //if xCoreID < 0 or CPU is unicore, it will use xTaskCreate, else xTaskCreatePinnedToCore

View file

@ -21,9 +21,9 @@ extern "C" {
/** Major version number (X.x.x) */ /** Major version number (X.x.x) */
#define ESP_ARDUINO_VERSION_MAJOR 3 #define ESP_ARDUINO_VERSION_MAJOR 3
/** Minor version number (x.X.x) */ /** Minor version number (x.X.x) */
#define ESP_ARDUINO_VERSION_MINOR 1 #define ESP_ARDUINO_VERSION_MINOR 2
/** Patch version number (x.x.X) */ /** Patch version number (x.x.X) */
#define ESP_ARDUINO_VERSION_PATCH 1 #define ESP_ARDUINO_VERSION_PATCH 0
/** /**
* Macro to convert ARDUINO version number into an integer * Macro to convert ARDUINO version number into an integer

View file

@ -31,7 +31,8 @@ void printRunningTasks(Print &printer) {
#endif #endif
configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0; configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0;
TaskStatus_t *pxTaskStatusArray = NULL; TaskStatus_t *pxTaskStatusArray = NULL;
volatile UBaseType_t uxArraySize = 0, x = 0; volatile UBaseType_t uxArraySize = 0;
uint32_t x = 0;
const char *taskStates[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"}; 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. // Take a snapshot of the number of tasks in case it changes while this function is executing.

View file

@ -18,16 +18,18 @@ The ESP32 is divided by family:
* ESP32 * ESP32
* Wi-Fi, BT and BLE 4 * Wi-Fi, BT and BLE 4
* ESP32-S2
* Wi-Fi only
* ESP32-S3
* Wi-Fi and BLE 5
* ESP32-C3 * ESP32-C3
* Wi-Fi and BLE 5 * Wi-Fi and BLE 5
* ESP32-C6 * ESP32-C6
* Wi-Fi, BLE 5 and IEEE 802.15.4 * Wi-Fi, BLE 5 and IEEE 802.15.4
* ESP32-H2 * ESP32-H2
* BLE 5 and IEEE 802.15.4 * BLE 5 and IEEE 802.15.4
* ESP32-P4
* 400 MHz Dual Core RISC-V CPU, 40 MHz ULP Co-processor, single-precision FPU and AI extensions.
* ESP32-S2
* Wi-Fi only
* ESP32-S3
* Wi-Fi and BLE 5
For each family, we have SoC variants with some differentiation. The differences are more about the embedded flash and its size and the number of the cores (dual or single). For each family, we have SoC variants with some differentiation. The differences are more about the embedded flash and its size and the number of the cores (dual or single).

View file

@ -2,16 +2,20 @@ Datasheet
--------- ---------
* `ESP32`_ (Datasheet) * `ESP32`_ (Datasheet)
* `ESP32-S2`_ (Datasheet) * `ESP32-C2`_ (Datasheet)
* `ESP32-C3`_ (Datasheet) * `ESP32-C3`_ (Datasheet)
* `ESP32-S3`_ (Datasheet)
* `ESP32-C6`_ (Datasheet) * `ESP32-C6`_ (Datasheet)
* `ESP32-H2`_ (Datasheet) * `ESP32-H2`_ (Datasheet)
* `ESP32-P4`_ (Datasheet)
* `ESP32-S2`_ (Datasheet)
* `ESP32-S3`_ (Datasheet)
.. _Espressif Product Selector: https://products.espressif.com/ .. _Espressif Product Selector: https://products.espressif.com/
.. _ESP32: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf .. _ESP32: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
.. _ESP32-S2: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf .. _ESP32-C2: https://www.espressif.com/sites/default/files/documentation/esp8684_datasheet_en.pdf
.. _ESP32-C3: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf .. _ESP32-C3: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf
.. _ESP32-S3: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf
.. _ESP32-C6: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf .. _ESP32-C6: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf
.. _ESP32-H2: https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf .. _ESP32-H2: https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf
.. _ESP32-P4: https://www.espressif.com/sites/default/files/documentation/esp32-p4_datasheet_en.pdf
.. _ESP32-S2: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf
.. _ESP32-S3: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf

View file

@ -15,6 +15,9 @@ Before Contributing
Before sending us a Pull Request, please consider this: Before sending us a Pull Request, please consider this:
* All contributions must be written in English to ensure effective communication and support.
Pull Requests written in other languages will be closed, with a request to rewrite them in English.
* Is the contribution entirely your own work, or is it already licensed under an LGPL 2.1 compatible Open Source License? * Is the contribution entirely your own work, or is it already licensed under an LGPL 2.1 compatible Open Source License?
If not, cannot accept it. If not, cannot accept it.
@ -318,7 +321,7 @@ ESP32-C3 target, you would run:
./.github/scripts/tests_build.sh -s uart -t esp32c3 ./.github/scripts/tests_build.sh -s uart -t esp32c3
You should see the output of the build process and the test binary should be generated in the ``~/.arduino/tests/<test_name>/build.tmp`` folder. You should see the output of the build process and the test binary should be generated in the ``~/.arduino/tests/<target_chip>/<test_name>/build.tmp`` folder.
Now that the test is built, you can run it in the target board. Connect the target board to your computer and run: Now that the test is built, you can run it in the target board. Connect the target board to your computer and run:
@ -339,7 +342,7 @@ The test will run on the target board and you should see the output of the test
lucassvaz@Lucas--MacBook-Pro esp32 % ./.github/scripts/tests_run.sh -s uart -t esp32c3 lucassvaz@Lucas--MacBook-Pro esp32 % ./.github/scripts/tests_run.sh -s uart -t esp32c3
Sketch uart test type: validation Sketch uart test type: validation
Running test: uart -- Config: Default Running test: uart -- Config: Default
pytest tests --build-dir /Users/lucassvaz/.arduino/tests/uart/build.tmp -k test_uart --junit-xml=/Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests/validation/uart/esp32c3/uart.xml --embedded-services esp,arduino pytest tests --build-dir /Users/lucassvaz/.arduino/tests/esp32c3/uart/build.tmp -k test_uart --junit-xml=/Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests/validation/uart/esp32c3/uart.xml --embedded-services esp,arduino
=============================================================================================== test session starts ================================================================================================ =============================================================================================== test session starts ================================================================================================
platform darwin -- Python 3.12.3, pytest-8.2.2, pluggy-1.5.0 platform darwin -- Python 3.12.3, pytest-8.2.2, pluggy-1.5.0
rootdir: /Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests rootdir: /Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests

View file

@ -38,17 +38,18 @@ Here are the ESP32 series supported by the Arduino-ESP32 project:
SoC Stable Development Datasheet SoC Stable Development Datasheet
========== ====== =========== ================================= ========== ====== =========== =================================
ESP32 Yes Yes `ESP32`_ ESP32 Yes Yes `ESP32`_
ESP32-S2 Yes Yes `ESP32-S2`_
ESP32-C3 Yes Yes `ESP32-C3`_ ESP32-C3 Yes Yes `ESP32-C3`_
ESP32-S3 Yes Yes `ESP32-S3`_
ESP32-C6 Yes Yes `ESP32-C6`_ ESP32-C6 Yes Yes `ESP32-C6`_
ESP32-H2 Yes Yes `ESP32-H2`_ ESP32-H2 Yes Yes `ESP32-H2`_
ESP32-P4 Yes Yes `ESP32-P4`_
ESP32-S2 Yes Yes `ESP32-S2`_
ESP32-S3 Yes Yes `ESP32-S3`_
========== ====== =========== ================================= ========== ====== =========== =================================
.. note:: .. note::
ESP32-C2 is also supported by Arduino-ESP32 but requires rebuilding the static libraries. ESP32-C2 is also supported by Arduino-ESP32 but requires using Arduino as an ESP-IDF component or rebuilding the static libraries.
This is not trivial and requires a good understanding of the ESP-IDF build system. For more information, see the `Arduino as an ESP-IDF component documentation <esp-idf_component.html>`_ or the
For more information, see the `Lib Builder documentation <lib_builder.html>`_. `Lib Builder documentation <lib_builder.html>`_, respectively.
See `Boards <boards/boards.html>`_ for more details about ESP32 development boards. See `Boards <boards/boards.html>`_ for more details about ESP32 development boards.
@ -102,7 +103,8 @@ Here are some community channels where you may find information and ask for some
- `ESP32 Forum`_: Official Espressif Forum. - `ESP32 Forum`_: Official Espressif Forum.
- `ESP32 Forum - Arduino`_: Official Espressif Forum for Arduino related discussions. - `ESP32 Forum - Arduino`_: Official Espressif Forum for Arduino related discussions.
- `ESP32 Forum - Hardware`_: Official Espressif Forum for Hardware related discussions. - `ESP32 Forum - Hardware`_: Official Espressif Forum for Hardware related discussions.
- `Gitter`_ - `Espressif Developer Portal`_: Official Espressif Developer Portal with tutorials, examples, workshops, and more.
- `Arduino Core for Espressif (Discord)`_: Official Espressif Discord channel for the Arduino Core.
- `Espressif MCUs (Discord)`_ - `Espressif MCUs (Discord)`_
- `ESP32 on Reddit`_ - `ESP32 on Reddit`_
@ -148,12 +150,13 @@ Resources
.. _Espressif Systems: https://www.espressif.com .. _Espressif Systems: https://www.espressif.com
.. _Espressif Product Selector: https://products.espressif.com/ .. _Espressif Product Selector: https://products.espressif.com/
.. _Espressif Developer Portal: https://developer.espressif.com/
.. _Arduino.cc: https://www.arduino.cc/en/Main/Software .. _Arduino.cc: https://www.arduino.cc/en/Main/Software
.. _Arduino Reference: https://www.arduino.cc/reference/en/ .. _Arduino Reference: https://www.arduino.cc/reference/en/
.. _ESP32 Forum: https://esp32.com .. _ESP32 Forum: https://esp32.com
.. _ESP32 Forum - Arduino: https://esp32.com/viewforum.php?f=19 .. _ESP32 Forum - Arduino: https://esp32.com/viewforum.php?f=19
.. _ESP32 Forum - Hardware: https://esp32.com/viewforum.php?f=12 .. _ESP32 Forum - Hardware: https://esp32.com/viewforum.php?f=12
.. _Gitter: https://gitter.im/espressif/arduino-esp32 .. _Arduino Core for Espressif (Discord): https://discord.gg/8xY6e9crwv
.. _Adafruit (Discord): https://discord.gg/adafruit .. _Adafruit (Discord): https://discord.gg/adafruit
.. _Espressif MCUs (Discord): https://discord.gg/nKxMTnkD .. _Espressif MCUs (Discord): https://discord.com/invite/XqnZPbF
.. _ESP32 on Reddit: https://www.reddit.com/r/esp32 .. _ESP32 on Reddit: https://www.reddit.com/r/esp32

View file

@ -10,6 +10,11 @@ Before Installing
We recommend you install the support using your favorite IDE, but other options are available depending on your operating system. We recommend you install the support using your favorite IDE, but other options are available depending on your operating system.
To install Arduino-ESP32 support, you can use one of the following options. To install Arduino-ESP32 support, you can use one of the following options.
.. note::
Users in China might have troubles with connection and download speeds using GitHub. Please use our Jihulab mirror as the repository source:
``https://jihulab.com/esp-mirror/espressif/arduino-esp32.git``
Installing using Arduino IDE Installing using Arduino IDE
---------------------------- ----------------------------
@ -32,6 +37,16 @@ This is the way to install Arduino-ESP32 directly from the Arduino IDE.
https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json
Users in China might have troubles with connection and download speeds using the links above. Please use our Jihulab mirror:
- Stable release link::
https://jihulab.com/esp-mirror/espressif/arduino-esp32/-/raw/gh-pages/package_esp32_index_cn.json
- Development release link::
https://jihulab.com/esp-mirror/espressif/arduino-esp32/-/raw/gh-pages/package_esp32_dev_index_cn.json
.. note:: .. note::
Starting with the Arduino IDE version 1.6.4, Arduino allows installation of third-party platform Starting with the Arduino IDE version 1.6.4, Arduino allows installation of third-party platform
packages using Boards Manager. We have packages available for Windows, macOS, and Linux. packages using Boards Manager. We have packages available for Windows, macOS, and Linux.

View file

@ -151,13 +151,13 @@ Set the build target(chip). ex. 'esp32s3'
This build command will build for the ESP32-S3 target. You can specify other targets. This build command will build for the ESP32-S3 target. You can specify other targets.
* esp32 * esp32
* esp32s2
* esp32s3
* esp32c2 * esp32c2
* esp32c3 * esp32c3
* esp32c6 * esp32c6
* esp32h2 * esp32h2
* esp32p4 * esp32p4
* esp32s2
* esp32s3
Set Build Type Set Build Type
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^

View file

@ -9,60 +9,68 @@ Supported Peripherals
Currently, the Arduino ESP32 supports the following peripherals with Arduino APIs. Currently, the Arduino ESP32 supports the following peripherals with Arduino APIs.
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Peripheral | ESP32 | S2 | C3 | S3 | C6 | H2 | Notes | | Peripheral | ESP32 | C3 | C6 | H2 | P4 | S2 | S3 | Notes |
+===============+=======+=======+=======+=======+=======+=======+=======+ +===============+=======+=======+=======+=======+=======+=======+=======+=======+
| ADC | Yes | Yes | Yes | Yes | Yes | Yes | | | ADC | Yes | Yes | Yes | Yes | Yes | Yes | Yes | (1) |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| BT Classic | Yes | N/A | N/A | N/A | N/A | N/A | | | BT Classic | Yes | N/A | N/A | N/A | N/A | N/A | N/A | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| BLE | Yes | N/A | Yes | Yes | Yes | Yes | | | BLE | Yes | Yes | Yes | Yes | No | N/A | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| DAC | Yes | Yes | N/A | N/A | N/A | N/A | | | DAC | Yes | N/A | N/A | N/A | Yes | Yes | N/A | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Ethernet | Yes | N/A | N/A | N/A | N/A | N/A | (*) | | Ethernet | Yes | N/A | N/A | N/A | Yes | N/A | N/A | (2) |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| GPIO | Yes | Yes | Yes | Yes | Yes | Yes | | | GPIO | Yes | Yes | Yes | Yes | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Hall Sensor | N/A | N/A | N/A | N/A | N/A | N/A | | | Hall Sensor | N/A | N/A | N/A | N/A | N/A | N/A | N/A | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| I2C | Yes | Yes | Yes | Yes | Yes | Yes | | | I2C | Yes | Yes | Yes | Yes | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| I2S | Yes | Yes | Yes | Yes | Yes | Yes | | | I2S | Yes | Yes | Yes | Yes | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| LEDC | Yes | Yes | Yes | Yes | Yes | Yes | | | LEDC | Yes | Yes | Yes | Yes | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Motor PWM | No | N/A | N/A | N/A | N/A | N/A | | | MIPI | N/A | N/A | N/A | N/A | No | N/A | N/A | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Pulse Counter | No | No | No | No | No | No | | | Motor PWM | No | N/A | N/A | N/A | N/A | N/A | N/A | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| RMT | Yes | Yes | Yes | Yes | Yes | Yes | | | MSPI | N/A | N/A | N/A | N/A | No | N/A | N/A | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| SDIO | No | No | No | No | No | No | | | Pulse Counter | No | No | No | No | No | No | No | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| SDMMC | Yes | N/A | N/A | Yes | N/A | N/A | | | RMT | Yes | Yes | Yes | Yes | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Timer | Yes | Yes | Yes | Yes | Yes | Yes | | | SDIO | No | No | No | No | No | No | No | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Temp. Sensor | N/A | Yes | Yes | Yes | Yes | Yes | | | SDMMC | Yes | N/A | N/A | N/A | N/A | N/A | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Touch | Yes | Yes | N/A | Yes | N/A | N/A | | | Timer | Yes | Yes | Yes | Yes | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| TWAI | No | No | No | No | No | No | | | Temp. Sensor | N/A | Yes | Yes | Yes | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| UART | Yes | Yes | Yes | Yes | Yes | Yes | | | Touch | Yes | N/A | N/A | N/A | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| USB | N/A | Yes | Yes | Yes | Yes | Yes | (**) | | TWAI | No | No | No | No | No | No | No | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Wi-Fi | Yes | Yes | Yes | Yes | Yes | N/A | | | UART | Yes | Yes | Yes | Yes | Yes | Yes | Yes | |
+---------------+-------+-------+-------+-------+-------+-------+-------+ +---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| USB | N/A | Yes | Yes | Yes | Yes | Yes | Yes | (3) |
+---------------+-------+-------+-------+-------+-------+-------+-------+-------+
| Wi-Fi | Yes | Yes | Yes | N/A | Yes | Yes | Yes | (4) |
+---------------+-------+-------+-------+-------+-------+-------+-------+-------+
Notes Notes
^^^^^ ^^^^^
(*) SPI Ethernet is supported by all ESP32 families and RMII only for ESP32. (1) ESP32-P4 calibration schemes not supported yet in IDF and ADC Continuous also lacks IDF support.
(**) ESP32-C3, C6, H2 only support USB CDC/JTAG (2) SPI Ethernet is supported by all ESP32 families and RMII only for ESP32 and ESP32-P4.
(3) ESP32-C3, C6, H2 only support USB CDC/JTAG
(4) ESP32-P4 only supports Wi-Fi through another SoC by using ``esp_hosted``.
.. note:: Some peripherals are not available for all ESP32 families. To see more details about it, see the corresponding SoC at `Product Selector <https://products.espressif.com>`_ page. .. note:: Some peripherals are not available for all ESP32 families. To see more details about it, see the corresponding SoC at `Product Selector <https://products.espressif.com>`_ page.

View file

@ -14,6 +14,23 @@ Installing
Here are the common issues during the installation. Here are the common issues during the installation.
Slow or unstable downloads
**************************
Users in China might have troubles with connection and download speeds using GitHub. Please use our Jihulab mirror as the repository source:
`https://jihulab.com/esp-mirror/espressif/arduino-esp32.git <https://jihulab.com/esp-mirror/espressif/arduino-esp32.git>`_
JSON files for the boards manager are available here:
- Stable release::
https://jihulab.com/esp-mirror/espressif/arduino-esp32/-/raw/gh-pages/package_esp32_index_cn.json
- Development release::
https://jihulab.com/esp-mirror/espressif/arduino-esp32/-/raw/gh-pages/package_esp32_dev_index_cn.json
Building Building
-------- --------

View file

@ -44,7 +44,7 @@ files:
- "platform.txt" - "platform.txt"
- "programmers.txt" - "programmers.txt"
dependencies: dependencies:
idf: ">=5.3,<5.4" idf: ">=5.3,<5.5"
# mdns 1.2.1 is necessary to build H2 with no WiFi # mdns 1.2.1 is necessary to build H2 with no WiFi
espressif/mdns: espressif/mdns:
version: "^1.2.3" version: "^1.2.3"
@ -52,12 +52,12 @@ dependencies:
espressif/esp_modem: espressif/esp_modem:
version: "^1.1.0" version: "^1.1.0"
espressif/esp-zboss-lib: espressif/esp-zboss-lib:
version: "==1.6.0" version: "==1.6.3"
require: public require: public
rules: rules:
- if: "target not in [esp32c2, esp32p4]" - if: "target not in [esp32c2, esp32p4]"
espressif/esp-zigbee-lib: espressif/esp-zigbee-lib:
version: "==1.6.0" version: "==1.6.3"
require: public require: public
rules: rules:
- if: "target not in [esp32c2, esp32p4]" - if: "target not in [esp32c2, esp32p4]"
@ -69,7 +69,7 @@ dependencies:
espressif/network_provisioning: espressif/network_provisioning:
version: "1.0.2" version: "1.0.2"
espressif/esp_rainmaker: espressif/esp_rainmaker:
version: "1.5.0" version: "1.5.2"
rules: rules:
- if: "target not in [esp32c2, esp32p4]" - if: "target not in [esp32c2, esp32p4]"
espressif/rmaker_common: espressif/rmaker_common:
@ -77,16 +77,16 @@ dependencies:
rules: rules:
- if: "target not in [esp32c2, esp32p4]" - if: "target not in [esp32c2, esp32p4]"
espressif/esp_insights: espressif/esp_insights:
version: "1.0.1" version: "1.2.2"
rules: rules:
- if: "target not in [esp32c2, esp32p4]" - if: "target not in [esp32c2, esp32p4]"
# New version breaks esp_insights 1.0.1 # New version breaks esp_insights 1.0.1
espressif/esp_diag_data_store: espressif/esp_diag_data_store:
version: "1.0.1" version: "1.0.2"
rules: rules:
- if: "target not in [esp32c2, esp32p4]" - if: "target not in [esp32c2, esp32p4]"
espressif/esp_diagnostics: espressif/esp_diagnostics:
version: "1.0.2" version: "1.2.1"
rules: rules:
- if: "target not in [esp32c2, esp32p4]" - if: "target not in [esp32c2, esp32p4]"
espressif/cbor: espressif/cbor:

4
idf_component_examples/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
build/
managed_components/
dependencies.lock
sdkconfig

View file

@ -8,6 +8,7 @@ set(PROJECT_VER_NUMBER 1)
# This should be done before using the IDF_TARGET variable. # This should be done before using the IDF_TARGET variable.
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
idf_build_set_property(MINIMAL_BUILD ON)
project(arduino_managed_component_light) project(arduino_managed_component_light)
# WARNING: This is just an example for using key for decrypting the encrypted OTA image # WARNING: This is just an example for using key for decrypting the encrypted OTA image
@ -20,7 +21,7 @@ if(CONFIG_IDF_TARGET_ESP32C2)
include(relinker) include(relinker)
endif() endif()
idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H" APPEND) idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++2a;-Os;-DCHIP_HAVE_CONFIG_H" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND) idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND)
# For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various # For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various
# flags that depend on -Wformat # flags that depend on -Wformat

View file

@ -59,15 +59,22 @@ Use ESP-IDF 5.1.4 from https://github.com/espressif/esp-idf/tree/release/v5.1
This example has been tested with Arduino Core 3.0.4 This example has been tested with Arduino Core 3.0.4
The project will download all necessary components, including the Arduino Core. The project will download all necessary components, including the Arduino Core.
Run `idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.<SOC>.idf" -p <PORT> flash monitor` Execute this sequence:
`<remove build folder> using linux rm command or Windows rmdir command`
`idf.py set-target <SoC_Target>`
`idf.py -D SDKCONFIG_DEFAULTS="sdkconfig_file1;sdkconfig_file2;sdkconfig_fileX" -p <PORT> flash monitor`
Example for ESP32-S3/Linux | macOS: Example for ESP32-S3/Linux | macOS:
``` ```
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32s3" -p /dev/ttyACM0 flash monitor rm -rf build
idf.py set-target esp32s3
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults" -p /dev/ttyACM0 flash monitor
``` ```
Example for ESP32-C3/Windows: Example for ESP32-C3/Windows:
``` ```
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32c3" -p com3 flash monitor rmdir /s/q build
idf.py set-target esp32c3
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults" -p com3 flash monitor
``` ```
It may be necessary to delete some folders and files before running `idf.py` It may be necessary to delete some folders and files before running `idf.py`
@ -95,11 +102,15 @@ In order to build the application that will use Thread Networking instead of Wi-
Example for ESP32-C6/Linux | macOS: Example for ESP32-C6/Linux | macOS:
``` ```
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.c6_thread" -p /dev/ttyACM0 flash monitor rm -rf build
idf.py set-target esp32c6
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.c6_thread" -p /dev/ttyACM0 flash monitor
``` ```
Example for ESP32-C6/Windows: Example for ESP32-C6/Windows:
``` ```
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.c6_thread" -p com3 flash monitor rmdir /s/q build
idf.py set-targt esp32c6
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.c6_thread" -p com3 flash monitor
``` ```
It may be necessary to delete some folders and files before running `idf.py` It may be necessary to delete some folders and files before running `idf.py`

View file

@ -0,0 +1,11 @@
{
"targets": {
"esp32c2": false,
"esp32s2": false
},
"requires": [
"CONFIG_SOC_WIFI_SUPPORTED=y",
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y",
"CONFIG_MBEDTLS_HKDF_C=y"
]
}

View file

@ -3,100 +3,40 @@ menu "Light Matter Accessory"
config BUTTON_PIN config BUTTON_PIN
int int
prompt "Button 1 GPIO" prompt "Button 1 GPIO"
default ENV_GPIO_BOOT_BUTTON default 9 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6
default 0
range -1 ENV_GPIO_IN_RANGE_MAX range -1 ENV_GPIO_IN_RANGE_MAX
help help
The GPIO pin for button that will be used to turn on/off the Matter Light. It shall be connected to a push button. It can use the BOOT button of the development board. The GPIO pin for button that will be used to turn on/off the Matter Light. It shall be connected to a push button. It can use the BOOT button of the development board.
endmenu endmenu
menu "LEDs" menu "LEDs"
config WS2812_PIN config WS2812_PIN
int int
prompt "WS2812 RGB LED GPIO" prompt "WS2812 RGB LED GPIO"
default ENV_GPIO_RGB_LED default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6
default 48
range -1 ENV_GPIO_OUT_RANGE_MAX range -1 ENV_GPIO_OUT_RANGE_MAX
help help
The GPIO pin for the Matter Light that will be driven by RMT. It shall be connected to one single WS2812 RGB LED. The GPIO pin for the Matter Light that will be driven by RMT. It shall be connected to one single WS2812 RGB LED.
endmenu endmenu
# TARGET CONFIGURATION config ENV_GPIO_RANGE_MIN
if IDF_TARGET_ESP32C3 int
config ENV_GPIO_RANGE_MIN default 0
int
default 0
config ENV_GPIO_RANGE_MAX config ENV_GPIO_RANGE_MAX
int int
default 19 default 19 if IDF_TARGET_ESP32C3
# GPIOs 20/21 are always used by UART in examples default 30 if IDF_TARGET_ESP32C6
default 48
config ENV_GPIO_IN_RANGE_MAX config ENV_GPIO_IN_RANGE_MAX
int int
default ENV_GPIO_RANGE_MAX default ENV_GPIO_RANGE_MAX
config ENV_GPIO_OUT_RANGE_MAX config ENV_GPIO_OUT_RANGE_MAX
int int
default ENV_GPIO_RANGE_MAX default ENV_GPIO_RANGE_MAX
config ENV_GPIO_BOOT_BUTTON
int
default 9
config ENV_GPIO_RGB_LED
int
default 8
endif
if IDF_TARGET_ESP32C6
config ENV_GPIO_RANGE_MIN
int
default 0
config ENV_GPIO_RANGE_MAX
int
default 30
# GPIOs 16/17 are always used by UART in examples
config ENV_GPIO_IN_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_OUT_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_BOOT_BUTTON
int
default 9
config ENV_GPIO_RGB_LED
int
default 8
endif
if IDF_TARGET_ESP32S3
config ENV_GPIO_RANGE_MIN
int
default 0
config ENV_GPIO_RANGE_MAX
int
default 48
config ENV_GPIO_IN_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_OUT_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_BOOT_BUTTON
int
default 0
config ENV_GPIO_RGB_LED
int
default 48
endif
endmenu endmenu

View file

@ -1,9 +1,9 @@
dependencies: dependencies:
espressif/esp_matter: espressif/esp_matter:
version: "^1.3.0" version: ">=1.3.0"
# Adds Arduino Core from GitHub repository using main branch # Adds Arduino Core from GitHub repository using main branch
espressif/arduino-esp32: espressif/arduino-esp32:
version: "^3.0.5" version: ">=3.0.5"
override_path: "../../../" override_path: "../../../"
pre_release: true pre_release: true

View file

@ -1,5 +1,3 @@
CONFIG_IDF_TARGET="esp32c3"
# Arduino Settings # Arduino Settings
CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_HZ=1000
CONFIG_AUTOSTART_ARDUINO=y CONFIG_AUTOSTART_ARDUINO=y

View file

@ -1,68 +1,5 @@
CONFIG_IDF_TARGET="esp32c6" CONFIG_IDF_TARGET="esp32c6"
# Arduino Settings
CONFIG_FREERTOS_HZ=1000
CONFIG_AUTOSTART_ARDUINO=y
# Log Levels
# Boot Messages - Log level
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
# Arduino Log Level
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
# IDF Log Level
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
# Default to 921600 baud when flashing and monitoring device
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_ESPTOOLPY_BAUD=921600
CONFIG_ESPTOOLPY_COMPRESSED=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
#enable BT
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
#disable BT connection reattempt
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
#enable lwip ipv6 autoconfig
CONFIG_LWIP_IPV6_AUTOCONFIG=y
# Use a custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
# Disable chip shell
CONFIG_ENABLE_CHIP_SHELL=n
# Enable OTA Requester
CONFIG_ENABLE_OTA_REQUESTOR=n
#enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# disable softap by default
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
CONFIG_ENABLE_WIFI_STATION=y
CONFIG_ENABLE_WIFI_AP=n
# Disable DS Peripheral
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
# Use compact attribute storage mode
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
# Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
# libsodium # libsodium
CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y

View file

@ -1,64 +0,0 @@
CONFIG_IDF_TARGET="esp32s3"
# Arduino Settings
CONFIG_FREERTOS_HZ=1000
CONFIG_AUTOSTART_ARDUINO=y
# Log Levels
# Boot Messages - Log level
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
# Arduino Log Level
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
# IDF Log Level
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
# Default to 921600 baud when flashing and monitoring device
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_ESPTOOLPY_BAUD=921600
CONFIG_ESPTOOLPY_COMPRESSED=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
#enable BT
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
#disable BT connection reattempt
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
#enable lwip ipv6 autoconfig
CONFIG_LWIP_IPV6_AUTOCONFIG=y
# Use a custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
# Disable chip shell
CONFIG_ENABLE_CHIP_SHELL=n
# Enable OTA Requester
CONFIG_ENABLE_OTA_REQUESTOR=n
#enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# disable softap by default
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
CONFIG_ENABLE_WIFI_STATION=y
CONFIG_ENABLE_WIFI_AP=n
# Disable DS Peripheral
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
# Use compact attribute storage mode
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
# Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6

View file

@ -5,4 +5,6 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
idf_build_set_property(MINIMAL_BUILD ON)
project(main) project(main)

View file

@ -9,4 +9,5 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake)
list(APPEND compile_definitions "ARDUINO_USB_CDC_ON_BOOT=1") list(APPEND compile_definitions "ARDUINO_USB_CDC_ON_BOOT=1")
list(APPEND compile_definitions "ARDUINO_USB_MODE=1") list(APPEND compile_definitions "ARDUINO_USB_MODE=1")
idf_build_set_property(MINIMAL_BUILD ON)
project(hw_cdc_hello_world) project(hw_cdc_hello_world)

View file

@ -0,0 +1,5 @@
{
"requires": [
"CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y"
]
}

View file

@ -1,5 +1,5 @@
name=ArduinoOTA name=ArduinoOTA
version=3.1.1 version=3.2.0
author=Ivan Grokhotkov and Hristo Gochkov author=Ivan Grokhotkov and Hristo Gochkov
maintainer=Hristo Gochkov <hristo@espressif.com> maintainer=Hristo Gochkov <hristo@espressif.com>
sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download. sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download.

View file

@ -29,7 +29,7 @@ ArduinoOTAClass::ArduinoOTAClass()
_start_callback(NULL), _end_callback(NULL), _error_callback(NULL), _progress_callback(NULL) {} _start_callback(NULL), _end_callback(NULL), _error_callback(NULL), _progress_callback(NULL) {}
ArduinoOTAClass::~ArduinoOTAClass() { ArduinoOTAClass::~ArduinoOTAClass() {
_udp_ota.stop(); end();
} }
ArduinoOTAClass &ArduinoOTAClass::onStart(THandlerFunction fn) { ArduinoOTAClass &ArduinoOTAClass::onStart(THandlerFunction fn) {

View file

@ -1,5 +1,5 @@
name=ESP32 Async UDP name=ESP32 Async UDP
version=3.1.1 version=3.2.0
author=Me-No-Dev author=Me-No-Dev
maintainer=Me-No-Dev maintainer=Me-No-Dev
sentence=Async UDP Library for ESP32 sentence=Async UDP Library for ESP32

View file

@ -1,5 +1,5 @@
name=BLE name=BLE
version=3.1.1 version=3.2.0
author=Neil Kolban <kolban1@kolban.com> author=Neil Kolban <kolban1@kolban.com>
maintainer=Dariusz Krempa <esp32@esp32.eu.org> maintainer=Dariusz Krempa <esp32@esp32.eu.org>
sentence=BLE functions for ESP32 sentence=BLE functions for ESP32

View file

@ -183,7 +183,7 @@ void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWh
* @brief Set the advertisement data that is to be published in a regular advertisement. * @brief Set the advertisement data that is to be published in a regular advertisement.
* @param [in] advertisementData The data to be advertised. * @param [in] advertisementData The data to be advertised.
*/ */
void BLEAdvertising::setAdvertisementData(BLEAdvertisementData &advertisementData) { bool BLEAdvertising::setAdvertisementData(BLEAdvertisementData &advertisementData) {
log_v(">> setAdvertisementData"); log_v(">> setAdvertisementData");
esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw((uint8_t *)advertisementData.getPayload().c_str(), advertisementData.getPayload().length()); esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw((uint8_t *)advertisementData.getPayload().c_str(), advertisementData.getPayload().length());
if (errRc != ESP_OK) { if (errRc != ESP_OK) {
@ -191,13 +191,14 @@ void BLEAdvertising::setAdvertisementData(BLEAdvertisementData &advertisementDat
} }
m_customAdvData = true; // Set the flag that indicates we are using custom advertising data. m_customAdvData = true; // Set the flag that indicates we are using custom advertising data.
log_v("<< setAdvertisementData"); log_v("<< setAdvertisementData");
return ESP_OK == errRc;
} // setAdvertisementData } // setAdvertisementData
/** /**
* @brief Set the advertisement data that is to be published in a scan response. * @brief Set the advertisement data that is to be published in a scan response.
* @param [in] advertisementData The data to be advertised. * @param [in] advertisementData The data to be advertised.
*/ */
void BLEAdvertising::setScanResponseData(BLEAdvertisementData &advertisementData) { bool BLEAdvertising::setScanResponseData(BLEAdvertisementData &advertisementData) {
log_v(">> setScanResponseData"); log_v(">> setScanResponseData");
esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw((uint8_t *)advertisementData.getPayload().c_str(), advertisementData.getPayload().length()); esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw((uint8_t *)advertisementData.getPayload().c_str(), advertisementData.getPayload().length());
if (errRc != ESP_OK) { if (errRc != ESP_OK) {
@ -205,6 +206,7 @@ void BLEAdvertising::setScanResponseData(BLEAdvertisementData &advertisementData
} }
m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data. m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data.
log_v("<< setScanResponseData"); log_v("<< setScanResponseData");
return ESP_OK == errRc;
} // setScanResponseData } // setScanResponseData
/** /**
@ -212,7 +214,7 @@ void BLEAdvertising::setScanResponseData(BLEAdvertisementData &advertisementData
* Start advertising. * Start advertising.
* @return N/A. * @return N/A.
*/ */
void BLEAdvertising::start() { bool BLEAdvertising::start() {
log_v(">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData); log_v(">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData);
// We have a vector of service UUIDs that we wish to advertise. In order to use the // We have a vector of service UUIDs that we wish to advertise. In order to use the
@ -225,7 +227,7 @@ void BLEAdvertising::start() {
m_advData.p_service_uuid = (uint8_t *)malloc(m_advData.service_uuid_len); m_advData.p_service_uuid = (uint8_t *)malloc(m_advData.service_uuid_len);
if (!m_advData.p_service_uuid) { if (!m_advData.p_service_uuid) {
log_e(">> start failed: out of memory"); log_e(">> start failed: out of memory");
return; return false;
} }
uint8_t *p = m_advData.p_service_uuid; uint8_t *p = m_advData.p_service_uuid;
@ -250,7 +252,7 @@ void BLEAdvertising::start() {
errRc = ::esp_ble_gap_config_adv_data(&m_advData); errRc = ::esp_ble_gap_config_adv_data(&m_advData);
if (errRc != ESP_OK) { if (errRc != ESP_OK) {
log_e("<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); log_e("<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return; return false;
} }
} }
@ -266,7 +268,7 @@ void BLEAdvertising::start() {
errRc = ::esp_ble_gap_config_adv_data(&m_scanRespData); errRc = ::esp_ble_gap_config_adv_data(&m_scanRespData);
if (errRc != ESP_OK) { if (errRc != ESP_OK) {
log_e("<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); log_e("<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return; return false;
} }
} }
@ -279,9 +281,10 @@ void BLEAdvertising::start() {
errRc = ::esp_ble_gap_start_advertising(&m_advParams); errRc = ::esp_ble_gap_start_advertising(&m_advParams);
if (errRc != ESP_OK) { if (errRc != ESP_OK) {
log_e("<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); log_e("<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return; } else {
log_v("<< start");
} }
log_v("<< start"); return ESP_OK == errRc;
} // start } // start
/** /**
@ -289,14 +292,15 @@ void BLEAdvertising::start() {
* Stop advertising. * Stop advertising.
* @return N/A. * @return N/A.
*/ */
void BLEAdvertising::stop() { bool BLEAdvertising::stop() {
log_v(">> stop"); log_v(">> stop");
esp_err_t errRc = ::esp_ble_gap_stop_advertising(); esp_err_t errRc = ::esp_ble_gap_stop_advertising();
if (errRc != ESP_OK) { if (errRc != ESP_OK) {
log_e("esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); log_e("esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return; } else {
log_v("<< stop");
} }
log_v("<< stop"); return ESP_OK == errRc;
} // stop } // stop
/** /**
@ -305,17 +309,17 @@ void BLEAdvertising::stop() {
* @param [in] Bluetooth address type. * @param [in] Bluetooth address type.
* Set BLE address. * Set BLE address.
*/ */
bool BLEAdvertising::setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type) {
void BLEAdvertising::setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type) {
log_v(">> setPrivateAddress"); log_v(">> setPrivateAddress");
m_advParams.own_addr_type = type; m_advParams.own_addr_type = type;
esp_err_t errRc = esp_ble_gap_set_rand_addr((uint8_t *)addr); esp_err_t errRc = esp_ble_gap_set_rand_addr((uint8_t *)addr);
if (errRc != ESP_OK) { if (errRc != ESP_OK) {
log_e("esp_ble_gap_set_rand_addr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); log_e("esp_ble_gap_set_rand_addr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return; } else {
log_v("<< setPrivateAddress");
} }
log_v("<< setPrivateAddress"); return ESP_OK == errRc;
} // setPrivateAddress } // setPrivateAddress
/** /**

View file

@ -54,18 +54,18 @@ public:
bool removeServiceUUID(int index); bool removeServiceUUID(int index);
bool removeServiceUUID(BLEUUID serviceUUID); bool removeServiceUUID(BLEUUID serviceUUID);
bool removeServiceUUID(const char *serviceUUID); bool removeServiceUUID(const char *serviceUUID);
void start(); bool start();
void stop(); bool stop();
void setAppearance(uint16_t appearance); void setAppearance(uint16_t appearance);
void setAdvertisementType(esp_ble_adv_type_t adv_type); void setAdvertisementType(esp_ble_adv_type_t adv_type);
void setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map); void setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map);
void setMaxInterval(uint16_t maxinterval); void setMaxInterval(uint16_t maxinterval);
void setMinInterval(uint16_t mininterval); void setMinInterval(uint16_t mininterval);
void setAdvertisementData(BLEAdvertisementData &advertisementData); bool setAdvertisementData(BLEAdvertisementData &advertisementData);
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly); void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
void setScanResponseData(BLEAdvertisementData &advertisementData); bool setScanResponseData(BLEAdvertisementData &advertisementData);
void setPrivateAddress(esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); void setPrivateAddress(esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM);
void setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); bool setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM);
void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
void setMinPreferred(uint16_t); void setMinPreferred(uint16_t);

View file

@ -1,5 +1,5 @@
name=BluetoothSerial name=BluetoothSerial
version=3.1.1 version=3.2.0
author=Evandro Copercini author=Evandro Copercini
maintainer=Evandro Copercini maintainer=Evandro Copercini
sentence=Simple UART to Classical Bluetooth bridge for ESP32 sentence=Simple UART to Classical Bluetooth bridge for ESP32

View file

@ -1,5 +1,5 @@
name=DNSServer name=DNSServer
version=3.1.1 version=3.2.0
author=Kristijan Novoselić author=Kristijan Novoselić
maintainer=Kristijan Novoselić, <kristijan.novoselic@gmail.com> maintainer=Kristijan Novoselić, <kristijan.novoselic@gmail.com>
sentence=A simple DNS server for ESP32. sentence=A simple DNS server for ESP32.

View file

@ -1,5 +1,5 @@
name=EEPROM name=EEPROM
version=3.1.1 version=3.2.0
author=Ivan Grokhotkov author=Ivan Grokhotkov
maintainer=Paolo Becchi <pbecchi@aerobusiness.it> maintainer=Paolo Becchi <pbecchi@aerobusiness.it>
sentence=Enables reading and writing data a sequential, addressable FLASH storage sentence=Enables reading and writing data a sequential, addressable FLASH storage

View file

@ -281,6 +281,8 @@ static esp_err_t stream_handler(httpd_req_t *req) {
int64_t fr_end = esp_timer_get_time(); int64_t fr_end = esp_timer_get_time();
int64_t frame_time = fr_end - last_frame; int64_t frame_time = fr_end - last_frame;
last_frame = fr_end;
frame_time /= 1000; frame_time /= 1000;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time); uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time);

View file

@ -1,260 +1,265 @@
//File: index_ov2640.html.gz, Size: 6578 //File: index_ov2640.html.gz, Size: 6687
#define index_ov2640_html_gz_len 6578 #define index_ov2640_html_gz_len 6687
const unsigned char index_ov2640_html_gz[] = { const unsigned char index_ov2640_html_gz[] = {
0x1F, 0x8B, 0x08, 0x08, 0x99, 0xA8, 0x7B, 0x67, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x6F, 0x76, 0x32, 0x36, 0x34, 0x30, 0x2E, 0x68, 0x74, 0x6D, 0x1F, 0x8B, 0x08, 0x08, 0xA5, 0xF6, 0xDA, 0x67, 0x00, 0xFF, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x6F, 0x76, 0x32, 0x36, 0x34, 0x30, 0x2E, 0x68, 0x74, 0x6D,
0x6C, 0x00, 0xED, 0x3D, 0x6B, 0x73, 0xDB, 0x46, 0x92, 0xDF, 0xFD, 0x2B, 0x60, 0x24, 0x6B, 0x92, 0x65, 0x92, 0x22, 0x29, 0x4A, 0x96, 0x15, 0x89, 0x3E, 0x5B, 0x6C, 0x2E, 0x67, 0x7A, 0x00, 0xED, 0x7D, 0x7B, 0x73, 0xDB, 0x36, 0xD6, 0xF7, 0xFF, 0xFD, 0x14, 0x8C, 0xDA, 0xB5, 0xE4, 0xB1, 0x24, 0xDB, 0xB2, 0xE3, 0x24,
0x56, 0x6C, 0xD7, 0xDA, 0x89, 0xD7, 0x4A, 0x1C, 0x6F, 0xA5, 0xB6, 0x6C, 0x10, 0x18, 0x92, 0x88, 0x41, 0x80, 0x0B, 0x80, 0xA2, 0x98, 0x94, 0x7E, 0xC7, 0xFD, 0x5E, 0x5B, 0x79, 0x72, 0x71, 0x93, 0xCE, 0x93, 0xB4, 0xDD, 0xBA, 0x97, 0xEC, 0xEC, 0xEC, 0xA4, 0x94, 0x08, 0x49, 0x6C, 0x28, 0x52, 0x4B, 0x52, 0xBE, 0xB4,
0xA0, 0xFB, 0x63, 0xD7, 0x3D, 0x0F, 0x60, 0x00, 0x0C, 0x5E, 0xA4, 0x4C, 0x7A, 0x7D, 0x47, 0xA7, 0x22, 0x3C, 0x7A, 0x7A, 0xFA, 0xDD, 0x3D, 0x33, 0x18, 0xE0, 0xE3, 0xCF, 0xF1, 0x7E, 0xA0, 0xE7, 0x8B, 0xED, 0xEF, 0x00, 0x20, 0x09, 0x92, 0xE0, 0x4D, 0xB2, 0xA5, 0x6C, 0xF7, 0x95, 0x34, 0x12, 0x05, 0x02, 0x07, 0x07,
0xEC, 0xBE, 0xE5, 0x99, 0xE1, 0x7A, 0x41, 0xB4, 0x59, 0x38, 0x77, 0x46, 0xF7, 0xCE, 0xD8, 0x1F, 0x0D, 0x7E, 0x67, 0x33, 0x62, 0x58, 0xEC, 0x90, 0x9E, 0xCE, 0xE7, 0x86, 0x83, 0x83, 0x0B, 0xCF, 0x1E, 0x59, 0xDE, 0x38, 0xBC, 0x5D, 0x30, 0x63, 0x16, 0xCE, 0x9D, 0xE1, 0x17, 0x67, 0xE2, 0xC7, 0xC0, 0xEB, 0x6C, 0xC6,
0x49, 0x68, 0x68, 0xE6, 0xCC, 0xF0, 0x03, 0x12, 0x9E, 0xEB, 0xCB, 0x70, 0xD2, 0x39, 0xD1, 0xD3, 0xB7, 0x5D, 0x63, 0x4E, 0xCE, 0xF5, 0x6B, 0x9B, 0xAC, 0x16, 0x4C, 0x4B, 0x5C, 0xF2, 0xBF, 0x73, 0x16, 0x9A, 0xC6, 0x78, 0x66, 0xFA, 0x01, 0x0B, 0xCF, 0x5B, 0xCB, 0x70, 0xD2, 0x7B, 0xDA, 0xCA, 0xDE, 0x76, 0xCD, 0x39,
0x9E, 0x1F, 0xEA, 0x9A, 0xE9, 0xB9, 0x21, 0x71, 0x01, 0x7C, 0x65, 0x5B, 0xE1, 0xEC, 0xDC, 0x22, 0xD7, 0xB6, 0x49, 0x3A, 0xF4, 0xA4, 0x6D, 0xBB, 0x76, 0x68, 0x3B, 0x6F, 0x5D, 0xD9, 0xEC, 0x7A, 0xE1, 0xF9, 0x61, 0xCB, 0x18, 0x7B, 0x6E, 0xC8, 0x5C, 0x64, 0xBF, 0xB6, 0xAD, 0x70, 0x76, 0x6E, 0xB1, 0x2B, 0x7B, 0xCC,
0x1B, 0x4E, 0x27, 0x30, 0x0D, 0x87, 0x9C, 0xF7, 0x65, 0x5C, 0xA1, 0x1D, 0x3A, 0x64, 0x74, 0x79, 0xF5, 0xF6, 0x70, 0xA0, 0xFD, 0xFC, 0x7E, 0x30, 0x3C, 0xEE, 0x7A, 0xFC, 0x4F, 0xD7, 0x76, 0xED, 0xD0, 0x36, 0x9D, 0x5E, 0x30, 0x36, 0x1D, 0x76, 0x7E, 0xA8, 0xC2, 0x0A, 0xED, 0xD0, 0x61, 0xC3, 0x8B, 0xCB, 0xEF, 0x8F,
0x9D, 0x1D, 0xB0, 0x6B, 0x31, 0x4C, 0x10, 0xAE, 0xE5, 0x73, 0xFC, 0x8D, 0x3D, 0x6B, 0xAD, 0xFD, 0x95, 0xB8, 0x84, 0xBF, 0x09, 0x10, 0xD1, 0x99, 0x18, 0x73, 0x06, 0xC6, 0x77, 0x3F, 0x0F, 0x4E, 0x8E, 0x0F, 0xCE, 0xF6, 0x45, 0x5A, 0x92, 0x27, 0x08, 0x6F, 0xD5, 0xFF, 0xF4, 0x1A, 0x79, 0xD6, 0xAD, 0xF1, 0x47, 0x2A,
0xDB, 0x59, 0x9F, 0x6A, 0x4F, 0x7D, 0xE8, 0xB3, 0xFD, 0x92, 0x38, 0xD7, 0x24, 0xB4, 0x4D, 0xA3, 0x1D, 0x18, 0x6E, 0xD0, 0x09, 0x88, 0x6F, 0x4F, 0x7E, 0xC8, 0x89, 0x5E, 0x13, 0x20, 0xD1, 0x9B, 0x98, 0x73, 0xDB, 0xB9, 0x3D, 0x35, 0x5E, 0xF8, 0xA8, 0xB3, 0xFB, 0x96, 0x39, 0x57, 0x2C, 0xB4, 0xC7, 0x66, 0x37, 0x30,
0x34, 0x1C, 0x1B, 0xE6, 0xE7, 0xA9, 0xEF, 0x2D, 0x5D, 0xEB, 0x54, 0xFB, 0xAE, 0x7F, 0x82, 0xFF, 0xB2, 0x40, 0xA6, 0xE7, 0x78, 0x3E, 0xDC, 0xBF, 0xFC, 0x11, 0xDD, 0xA0, 0x17, 0x30, 0xDF, 0x9E, 0xFC, 0x35, 0x57, 0x70, 0x64, 0x8E, 0x3F, 0x4D, 0x7D, 0x6F, 0xE9, 0x5A, 0xA7, 0xC6, 0x97, 0x87, 0x4F, 0xE9, 0x9D, 0xCF,
0xFF, 0x65, 0xEF, 0xD3, 0xDE, 0x03, 0xFB, 0x4F, 0x72, 0xAA, 0xF5, 0x8F, 0x17, 0x37, 0x89, 0xFB, 0xB7, 0xF7, 0x12, 0xA7, 0xB3, 0x41, 0x1E, 0xF5, 0xBC, 0xFD, 0x34, 0xF6, 0x1C, 0xCF, 0xC7, 0xFD, 0x8B, 0xAF, 0xE9, 0x9D, 0xBF, 0xCF, 0x6B, 0x0F, 0xEC, 0xDF, 0xD9, 0xA9, 0x71, 0x78, 0xB2, 0xB8, 0x49, 0xDD, 0xBF, 0xFB,
0x49, 0x71, 0xFB, 0x80, 0x98, 0xA1, 0xED, 0xB9, 0xDD, 0xB9, 0x61, 0xBB, 0x0A, 0x4C, 0x96, 0x1D, 0x2C, 0x1C, 0x03, 0x64, 0x30, 0x71, 0x48, 0x21, 0x9E, 0xEF, 0x22, 0xF5, 0x77, 0x36, 0x28, 0xC2, 0x5E, 0x96, 0x7F, 0x5A, 0x5E, 0x3E, 0x60, 0xE3, 0xD0, 0xF6, 0xDC, 0xFE, 0xDC, 0xB4, 0x5D, 0x0D, 0x24, 0xCB, 0x0E, 0x16,
0xE6, 0xC4, 0x5D, 0xB6, 0x4B, 0xB0, 0x21, 0x92, 0x8E, 0x65, 0xFB, 0x0C, 0xEA, 0x14, 0xE5, 0xB0, 0x9C, 0xBB, 0xA5, 0x68, 0x8B, 0xE8, 0x72, 0x3D, 0x97, 0x28, 0x8E, 0x09, 0x1A, 0x4C, 0x1C, 0x56, 0x0A, 0xE7, 0xCB, 0x39, 0x73, 0x97, 0xDD, 0x0A, 0x68, 0x04, 0xA4, 0x67, 0xD9, 0xBE, 0xC8, 0x75, 0x4A, 0x74, 0x58, 0xCE,
0x04, 0x88, 0x1D, 0xAD, 0x7C, 0x63, 0x81, 0x00, 0xF8, 0x37, 0x0B, 0x32, 0xB7, 0x5D, 0x66, 0x54, 0xA7, 0xDA, 0xE1, 0xB0, 0xB7, 0xB8, 0x29, 0x51, 0xE5, 0xE1, 0xDD, 0x4A, 0xB0, 0x65, 0x78, 0xB9, 0x9E, 0xCB, 0x34, 0x04, 0xA4, 0x8A, 0xAE, 0x7D, 0x73, 0x41, 0x19, 0xE8, 0x37, 0x9F, 0x65, 0x6E, 0xBB, 0x42, 0xA8, 0x4E,
0x31, 0xFE, 0xCB, 0x02, 0x2D, 0x0C, 0xCB, 0xB2, 0xDD, 0xE9, 0xA9, 0x76, 0xA2, 0x44, 0xE1, 0xF9, 0x16, 0xF1, 0x3B, 0xBE, 0x61, 0xD9, 0xCB, 0xE0, 0x54, 0x1B, 0x8D, 0xA3, 0xE3, 0x83, 0xC5, 0x4D, 0x05, 0x2B, 0x8F, 0x4E, 0xE8, 0x9D, 0xCF, 0xB4, 0x30, 0x2D, 0xCB, 0x76, 0xA7, 0xA7, 0x06, 0xE8, 0xAC, 0x01, 0xE1, 0xF9,
0xAA, 0x60, 0xE6, 0x86, 0x3F, 0x05, 0x5A, 0x42, 0x0F, 0x88, 0xED, 0xF4, 0x95, 0x94, 0x70, 0x10, 0xDF, 0x9E, 0xCE, 0x42, 0x50, 0x69, 0x06, 0x26, 0x2D, 0x34, 0x16, 0xF3, 0x7B, 0xBE, 0x69, 0xD9, 0xCB, 0xE0, 0xD4, 0x38, 0xD6, 0xE5, 0x99, 0x9B, 0xFE, 0x14, 0xB8, 0x84, 0x1E, 0x90, 0xED, 0x1D, 0x6A, 0x31, 0x91, 0x59,
0xEE, 0x42, 0x65, 0xFA, 0x2C, 0x94, 0x9B, 0x5A, 0x6A, 0x86, 0x63, 0x4F, 0xDD, 0x8E, 0x1D, 0x92, 0x39, 0xB0, 0x13, 0x84, 0x3E, 0x09, 0xCD, 0x59, 0x11, 0x29, 0x7C, 0x7B, 0x3A, 0x0B, 0xC1, 0xD2, 0x5C, 0x9E, 0x2C, 0xD1, 0xA4, 0x0A, 0x55, 0xF1, 0xB3, 0x94, 0x6E, 0x7A, 0xAA, 0x99, 0x8E, 0x3D, 0x75, 0x7B, 0x76, 0xC8,
0x13, 0x7B, 0xBA, 0xF4, 0x89, 0x82, 0x90, 0x48, 0x6E, 0x05, 0x0C, 0xC3, 0xCD, 0xEC, 0xAD, 0xCE, 0x8A, 0x8C, 0x3F, 0xDB, 0x61, 0x87, 0xCB, 0x64, 0x4C, 0x26, 0xE6, 0x68, 0x4E, 0x10, 0xFA, 0x2C, 0x1C, 0xCF, 0xCA, 0x50, 0x99, 0xD8, 0xD3, 0xA5, 0xCF, 0x34, 0x88, 0xC4, 0x74, 0x2B, 0x69, 0x30, 0x6E, 0xE6, 0x6F, 0xF5,
0x9E, 0x4F, 0x94, 0x90, 0x02, 0xC2, 0xF1, 0xCC, 0xCF, 0x9D, 0x20, 0x34, 0xFC, 0xB0, 0x0A, 0x42, 0x63, 0x12, 0x12, 0xBF, 0x1C, 0x1F, 0x41, 0xAB, 0x28, 0xC7, 0xAE, 0xD9, 0xE8, 0x93, 0x1D, 0xF6, 0x24, 0x4D, 0x46, 0x6C, 0xE2, 0xF9, 0x90, 0x73, 0x4D, 0xCE, 0x28, 0x87, 0xE3, 0x8D, 0x3F, 0xF5, 0x82, 0xD0, 0xF4, 0x41,
0x96, 0xDF, 0x2D, 0x07, 0xB0, 0x5D, 0xC7, 0x76, 0x49, 0x75, 0xF2, 0xF2, 0xFA, 0x4D, 0xA2, 0x63, 0x50, 0x15, 0x14, 0x63, 0xCF, 0xA7, 0x45, 0x56, 0x42, 0x79, 0xBB, 0x6A, 0x80, 0xE6, 0x24, 0x64, 0xD0, 0xCD, 0x2A, 0x78, 0x8C, 0xA4, 0xA2, 0x1A, 0x5A, 0x71, 0xB5, 0x32, 0x83, 0xED, 0x3A, 0xB6, 0xCB, 0xEA, 0xA3, 0x57,
0xCD, 0x76, 0xC6, 0xFD, 0xA6, 0xDF, 0xEB, 0xFD, 0x2D, 0x7B, 0x73, 0x46, 0x98, 0x99, 0x1A, 0xCB, 0xD0, 0xDB, 0xDE, 0x23, 0x32, 0x6E, 0x95, 0xE2, 0xE3, 0xBF, 0x54, 0x6F, 0x1A, 0x9C, 0xC8, 0x55, 0x83, 0x31, 0xF6, 0x7C, 0x5A, 0x26, 0x25, 0xBC, 0xAD, 0xF9, 0xCA, 0xA4, 0xDE, 0x1C, 0x1E, 0x1C, 0xFC, 0x25, 0x7F, 0x73,
0xE6, 0xC4, 0xB2, 0x0D, 0xAD, 0x29, 0xB9, 0xF3, 0x49, 0x0F, 0x6C, 0xAA, 0xA5, 0x19, 0xAE, 0xA5, 0x35, 0x3D, 0xDF, 0x06, 0x47, 0x30, 0x68, 0xB8, 0x71, 0xE0, 0xC6, 0x84, 0x98, 0x9A, 0xCB, 0xD0, 0x5B, 0x5F, 0x23, 0x72, 0x6A, 0x95, 0x69, 0xC7, 0xFF, 0xCC, 0x99, 0x65, 0x9B, 0x46, 0x47, 0x51, 0xE7, 0xA7, 0x07, 0x90,
0x0A, 0x24, 0x8E, 0x05, 0x69, 0x29, 0x58, 0x2E, 0xF0, 0x19, 0x59, 0x22, 0x6A, 0xB7, 0xC1, 0x5F, 0x85, 0x90, 0x83, 0xBF, 0x52, 0x07, 0x52, 0xF0, 0x48, 0xD1, 0xA9, 0x5D, 0xC3, 0x74, 0x2D, 0xA3, 0xE3, 0xF9, 0x36, 0x14, 0xC1, 0xE4, 0xE6, 0xC6, 0x41, 0x0A, 0x3A, 0x8E, 0x05, 0xDB, 0xD5, 0x34, 0xB9, 0x44, 0x67, 0x54,
0x17, 0xE9, 0x4B, 0xA6, 0x30, 0x4F, 0x67, 0xF8, 0x9B, 0x1B, 0x37, 0x9D, 0x42, 0xDD, 0x09, 0x20, 0xA1, 0x43, 0x48, 0xB3, 0x66, 0x13, 0x40, 0xAF, 0x67, 0x5A, 0x8A, 0xE8, 0xD5, 0xA6, 0xA6, 0xC9, 0xA9, 0xA5, 0x40, 0x9A, 0x36, 0x56, 0xF2, 0xAB, 0x0E, 0xCF, 0x04, 0x61, 0x81, 0x62, 0x19, 0xEF, 0xA2, 0x4C, 0x11, 0x0F,
0x47, 0xC3, 0x28, 0xD9, 0x52, 0xB7, 0xE1, 0x48, 0xD5, 0x2A, 0xC7, 0x9F, 0x6C, 0x14, 0x35, 0xD8, 0x55, 0xB3, 0x1A, 0xC7, 0x0E, 0xF6, 0x4F, 0x65, 0x43, 0x8C, 0xD1, 0xCD, 0x8E, 0x3B, 0xC8, 0x7A, 0x35, 0x33, 0x7A, 0x06, 0x59, 0xC9, 0x5D, 0x7D, 0x19, 0x09, 0x54, 0xCF, 0xF2, 0xAC, 0x50, 0x34, 0x68, 0xAE, 0xBE, 0xA9,
0x93, 0xDC, 0x28, 0x82, 0xBF, 0xEA, 0x91, 0x24, 0x46, 0x56, 0x1A, 0x4D, 0x14, 0x88, 0xF3, 0x23, 0x4A, 0x06, 0x6F, 0x9E, 0x77, 0x2B, 0xB0, 0x16, 0x93, 0x50, 0x89, 0xED, 0x10, 0x6F, 0x9D, 0x0C, 0x55, 0x58, 0x91, 0x66, 0x96, 0xA4, 0x81, 0x35, 0x69, 0x64, 0x51, 0x6A, 0x5B, 0x95, 0x46, 0x96, 0xA5, 0x89, 0x75, 0x69,
0x35, 0xBA, 0x28, 0x10, 0x17, 0xD1, 0x50, 0x1A, 0x65, 0xF0, 0x77, 0x5B, 0xA1, 0xDE, 0xF8, 0x6E, 0xBC, 0x0C, 0x43, 0xCF, 0x0D, 0xB6, 0x4A, 0x51, 0x79, 0x7E, 0x60, 0x61, 0x6A, 0x59, 0x19, 0xC1, 0xCE, 0x6A, 0x7F, 0xE3, 0xCB, 0xD1, 0x32, 0x0C, 0x3D, 0x37, 0x58, 0xAB, 0x8B, 0x2A, 0xD2, 0xB3, 0xDF, 0x96, 0x41, 0x68,
0xF6, 0xC7, 0x32, 0x08, 0xED, 0xC9, 0xBA, 0xC3, 0x5D, 0x1A, 0xFC, 0x6C, 0x61, 0x40, 0x09, 0x39, 0x26, 0xE1, 0x8A, 0x90, 0xE2, 0x72, 0xC3, 0x35, 0xAE, 0x21, 0x4F, 0x6E, 0x7B, 0x52, 0xA5, 0xA1, 0x67, 0x0B, 0x13, 0x2E, 0xE4, 0x88, 0x85, 0xD7, 0x8C, 0x95, 0xBB, 0x1B, 0xAE, 0x79, 0x05, 0xBB, 0x33, 0x9D, 0x3A, 0x3A,
0xEE, 0x4C, 0xA7, 0x8E, 0xCA, 0xF6, 0xCC, 0xA5, 0x1F, 0x60, 0xDD, 0xB6, 0xF0, 0x6C, 0x40, 0xEC, 0x67, 0x3B, 0x4E, 0xFA, 0x60, 0xC5, 0x8E, 0x3A, 0xE6, 0x58, 0xD9, 0x1B, 0x2F, 0xFD, 0x80, 0xFC, 0xB6, 0x85, 0x67, 0x03, 0xB0, 0x9F, 0xAF, 0x38, 0xAD, 0x83, 0x35, 0x2B, 0xEA, 0x8D, 0x47, 0x9A, 0xBA, 0xBC, 0x65, 0x48,
0xD1, 0x97, 0xB7, 0x0C, 0x51, 0xC6, 0x4A, 0x4D, 0x78, 0xC0, 0x8E, 0x1D, 0xAE, 0x95, 0xF7, 0xB8, 0x27, 0x2A, 0xEE, 0x08, 0x17, 0x2C, 0x4C, 0x0B, 0x49, 0xBA, 0x34, 0xD6, 0x72, 0xC2, 0x43, 0x73, 0xEC, 0x10, 0xD5, 0x68, 0xEE, 0x49, 0x4D, 0xD4, 0xDC, 0x89, 0x54, 0xB0, 0xB4, 0x5B, 0x48, 0xE3, 0x75, 0x3A, 0x9E, 0xB1,
0x4E, 0xCD, 0x19, 0x31, 0x3F, 0x13, 0xEB, 0x61, 0x69, 0x19, 0x56, 0x56, 0x1E, 0x76, 0x6D, 0x77, 0xB1, 0x0C, 0x3B, 0x58, 0x4E, 0x2D, 0xBE, 0x88, 0xCE, 0xA9, 0xF1, 0x27, 0x66, 0xED, 0x55, 0xBA, 0x61, 0x55, 0xEE, 0x61, 0xDF, 0x76, 0x17, 0xCB, 0xB0, 0x47, 0xEE, 0xD4, 0xE2, 0x41, 0x78, 0xCE, 0x05, 0x32, 0x6A, 0xE2,
0x41, 0x0A, 0x16, 0x07, 0x83, 0xA2, 0xA2, 0xE2, 0x68, 0x71, 0x53, 0x2C, 0x04, 0x99, 0xD8, 0x91, 0x63, 0x8C, 0x89, 0x53, 0x44, 0x32, 0x77, 0x86, 0x9C, 0xB0, 0x60, 0x50, 0xE6, 0x54, 0x3C, 0x5E, 0xDC, 0x94, 0x13, 0x41, 0x45, 0x76, 0xE8, 0x98, 0x23, 0xE6, 0x94, 0xA1, 0x2C, 0x95, 0xA1, 0xC0, 0xEC, 0x4A, 0x5B, 0x55,
0xCB, 0x63, 0x55, 0x7E, 0xED, 0x46, 0x29, 0x8B, 0x93, 0xD7, 0xF0, 0xD1, 0xDF, 0x2A, 0xCB, 0x91, 0x1E, 0xB7, 0x13, 0x97, 0x02, 0xE2, 0x80, 0x83, 0xE5, 0x95, 0xEC, 0xBB, 0x65, 0x7C, 0xD1, 0xE3, 0x27, 0x7F, 0xA9, 0x4D, 0x47, 0x7E, 0xDD, 0x4D, 0x25, 0x05, 0xCC, 0x81, 0x82, 0x15, 0xB9, 0xDE, 0xC8, 0x73, 0x0D, 0x1C,
0xDE, 0x00, 0xB3, 0x02, 0x1A, 0x0A, 0x3B, 0xF0, 0x0D, 0x77, 0x4A, 0x20, 0x16, 0xDC, 0xB4, 0xC5, 0x61, 0xF1, 0xC0, 0xA0, 0x12, 0xFB, 0x18, 0xAA, 0x8F, 0x8A, 0x4A, 0x2B, 0xF0, 0x4D, 0x77, 0xCA, 0x60, 0x0B, 0x6E, 0xBA, 0xD1, 0x65, 0xF9, 0xC0, 0xA0, 0x56, 0xF3, 0xC9, 0x54, 0x83, 0xEC, 0x65, 0x15, 0x0B, 0x83, 0xD0,
0x07, 0x22, 0x2C, 0x20, 0xB4, 0xB5, 0x2E, 0x3B, 0xD8, 0xA0, 0x2A, 0x91, 0xF4, 0x5B, 0x48, 0x48, 0x5F, 0x69, 0x1D, 0xAC, 0x30, 0x51, 0x7A, 0x4E, 0xD2, 0xB6, 0x35, 0xFA, 0xE2, 0x62, 0x05, 0xAF, 0x44, 0xE1, 0x6F, 0x29, 0x22, 0x87, 0x5A, 0xE9, 0x10, 0x8E, 0x89, 0x56, 0x73, 0xD2, 0xB2, 0xA5, 0x75, 0xF4, 0x2B, 0x4D,
0x94, 0x85, 0x7E, 0x69, 0x68, 0x10, 0x43, 0xBE, 0xC9, 0xA4, 0x6C, 0xD0, 0x38, 0x99, 0x1C, 0xF6, 0x0E, 0x87, 0xA5, 0x95, 0x93, 0x92, 0xCB, 0xD4, 0xC0, 0x51, 0x43, 0x34, 0xE4, 0x9B, 0x4C, 0xAA, 0x06, 0x8D, 0x93, 0xC9, 0xD1, 0xC1, 0xD1, 0x71, 0xA5, 0xE7, 0xA4, 0x6D, 0x65, 0x66, 0xE0, 0xA8, 0x31, 0x1D, 0xB1, 0x59,
0x11, 0x3A, 0xA2, 0xB0, 0x52, 0x68, 0x04, 0x81, 0x71, 0xAD, 0x2C, 0xDA, 0xBD, 0xC0, 0x66, 0x23, 0x37, 0x63, 0x1C, 0xC0, 0xD8, 0x2D, 0x54, 0x0C, 0xBD, 0xB8, 0x29, 0x15, 0x82, 0xC0, 0xBC, 0xD2, 0x3A, 0xED, 0x5E, 0x80, 0xF1, 0x37, 0x8D, 0xDC, 0xCC, 0x51, 0x80, 0xB1, 0x5B, 0xA8, 0x19, 0x7A, 0x49, 0x41, 0x1F, 0x68,
0xA1, 0x0F, 0x94, 0xF4, 0xD1, 0x92, 0x4E, 0xE9, 0x02, 0x42, 0xBC, 0x6A, 0xB2, 0x13, 0x1A, 0x50, 0x83, 0x48, 0x0A, 0x56, 0x16, 0x95, 0x21, 0xB9, 0x09, 0x3B, 0xF1, 0xE3, 0x2E, 0x9D, 0x56, 0x05, 0x22, 0xF2, 0xEA, 0xD1, 0x4E, 0x71, 0x40, 0x9F, 0x45, 0x61, 0xB0, 0xD6, 0xA9, 0x0C, 0xD9, 0x4D, 0xD8, 0xB3, 0xD8, 0xD8,
0x16, 0x31, 0x3D, 0x9F, 0x55, 0x83, 0x39, 0x23, 0xC7, 0x94, 0x22, 0xCB, 0x2D, 0xF6, 0x74, 0xE6, 0x5D, 0x13, 0x5F, 0x21, 0xAC, 0x94, 0x52, 0x87, 0x8F, 0x87, 0xF3, 0x85, 0x37, 0x58, 0x30, 0x72, 0xCC, 0x30, 0xB2, 0x5A, 0x62, 0x4F, 0x67, 0xDE, 0x15, 0xF3, 0x35, 0xC4, 0xCA, 0x30, 0xF5, 0xF8, 0xD9, 0xB1, 0x55, 0x03,
0x56, 0x05, 0x6C, 0x06, 0xA4, 0x47, 0xA5, 0xEC, 0x93, 0xE8, 0x06, 0x7D, 0x73, 0x50, 0xE8, 0xC7, 0x0C, 0x5D, 0x17, 0x7C, 0xC6, 0x18, 0x3B, 0xC4, 0x2A, 0xC8, 0x9A, 0x89, 0xEE, 0x51, 0x4B, 0xFB, 0x34, 0xB8, 0xC1, 0xE1, 0x78, 0x50, 0xAA, 0xC7, 0x02, 0x5C, 0x1F, 0x3A, 0x63, 0x8E, 0x1C, 0x66, 0x95, 0xF4, 0x66, 0x16,
0x66, 0x16, 0x99, 0x18, 0x4B, 0x27, 0x2C, 0xB1, 0x4A, 0xA3, 0x87, 0xFF, 0x8A, 0x7A, 0xA4, 0x61, 0xE8, 0x77, 0x9C, 0x17, 0x3A, 0xA7, 0x81, 0xE3, 0x5F, 0x8A, 0x9B, 0x98, 0x4B, 0x27, 0xAC, 0x90, 0x4A, 0xF3, 0x80, 0xDE, 0x65, 0x35, 0x72, 0x33, 0xF4, 0x0F, 0x8A, 0x0B, 0x9D, 0x73, 0xC3, 0xF1, 0x4F, 0x4D, 0x9D, 0x91,
0x3E, 0x45, 0xA9, 0x61, 0x2C, 0x16, 0xC4, 0x00, 0x28, 0x93, 0xE4, 0xE9, 0xA1, 0xD2, 0x10, 0x43, 0x1D, 0xE7, 0x2B, 0x8D, 0xDB, 0x4B, 0x1D, 0x36, 0x2A, 0x1E, 0xAB, 0x61, 0x2E, 0x16, 0xCC, 0x44, 0xAE, 0x31, 0x24, 0x51, 0xCF, 0x87, 0x5A, 0x43, 0x0C, 0xBD, 0x9D, 0xAF, 0x35, 0x6E, 0xAF, 0x54, 0xD8, 0xD8, 0x79, 0x6C,
0x6B, 0xF1, 0x7C, 0x3A, 0xF1, 0xCC, 0xA5, 0xAA, 0xAA, 0xA9, 0xE6, 0x78, 0x59, 0x7C, 0xA7, 0x42, 0x64, 0x81, 0x63, 0x53, 0xF7, 0x5F, 0xBA, 0x2E, 0x6A, 0xB4, 0xD4, 0xE6, 0xD3, 0x89, 0x37, 0x5E, 0xEA, 0xBC, 0x9A, 0x7A, 0x8A, 0x97, 0x87, 0x77, 0x1A, 0x91, 0x2C, 0x70, 0x6C, 0xAE, 0xFE, 0x4B, 0xD7, 0x25, 0x8E, 0xF6,
0x13, 0xFA, 0xC0, 0xA6, 0xA2, 0xA3, 0x6A, 0x82, 0xDB, 0x28, 0x86, 0x25, 0x04, 0x9B, 0x37, 0x77, 0x95, 0x0A, 0x53, 0x8A, 0x70, 0x1A, 0x45, 0x5A, 0x0D, 0x62, 0x42, 0x1F, 0xCD, 0xD4, 0x54, 0x54, 0x8F, 0x70, 0x2B, 0xD9, 0xB0, 0x14, 0x61, 0x8B, 0x62, 0x57, 0x19, 0x33, 0xA5, 0x31, 0xA7, 0xB1, 0xA5, 0x35, 0x60, 0x43,
0x88, 0x6D, 0x09, 0x54, 0xDB, 0xC9, 0x25, 0x9C, 0x2D, 0xE7, 0xAA, 0x3A, 0x4A, 0x74, 0xD6, 0x87, 0xA4, 0xCF, 0xBA, 0xF3, 0xA7, 0x63, 0xA3, 0xD9, 0x6B, 0xF7, 0x6C, 0x2B, 0x02, 0xB5, 0x1E, 0x5D, 0xC2, 0xD9, 0x72, 0xAE, 0xF3, 0xA3, 0xA2, 0xCA, 0x0E, 0xD1, 0xE9, 0x8B, 0xEA, 0xFC, 0xE9, 0xC8, 0xEC, 0x1C, 0x74, 0x0F,
0xDA, 0x87, 0xF0, 0x3F, 0xC5, 0x78, 0xA6, 0xD8, 0xB8, 0xB8, 0x78, 0x73, 0x2C, 0x2F, 0x15, 0xA2, 0xCB, 0xA7, 0x95, 0xF2, 0x82, 0x7D, 0xA9, 0x2E, 0xAA, 0x7B, 0xBA, 0x47, 0xF8, 0xD2, 0x8C, 0x67, 0xCA, 0x85, 0x4B, 0x92, 0xB7, 0x40, 0xF2, 0x32, 0x26, 0xBA, 0x3A, 0xAC, 0x54, 0x64, 0xEC, 0x2B, 0x79, 0x51, 0x5F, 0x93,
0x52, 0x72, 0x7E, 0xA9, 0xDF, 0x2D, 0xC9, 0xC3, 0x39, 0x26, 0x5D, 0xDF, 0x10, 0x15, 0xD6, 0x52, 0x57, 0xC5, 0x73, 0xEF, 0xCF, 0x0E, 0x2B, 0x42, 0xFE, 0xCF, 0xD2, 0xF1, 0xA5, 0xC3, 0x7E, 0x45, 0x3F, 0x5C, 0x20, 0xD2, 0xCD, 0x05, 0x51, 0x23, 0x2D, 0x4D, 0x59, 0x3C, 0xF7, 0x7E, 0x07, 0x31, 0xC9, 0x09, 0xF9, 0xAF,
0x5B, 0xBB, 0x24, 0x8A, 0x6F, 0xDA, 0xD2, 0x6B, 0xCB, 0x25, 0xD8, 0xB7, 0x6D, 0xF4, 0xF2, 0xB5, 0xDE, 0xE1, 0x55, 0x1F, 0x50, 0xE8, 0xC2, 0x18, 0xD4, 0x87, 0x97, 0x76, 0x85, 0x14, 0x7F, 0x6A, 0x49, 0x6F, 0x4C, 0x97, 0x60, 0xDB, 0xB2, 0x81, 0x00, 0x44, 0x21, 0x7D, 0xA4, 0xD7, 0x07, 0x0C, 0x5D, 0x8C, 0x41, 0x7D,
0xC1, 0x68, 0x6E, 0x65, 0x28, 0xC1, 0x6C, 0x20, 0x83, 0x89, 0xED, 0x38, 0x1D, 0xC7, 0x5B, 0x95, 0x57, 0x22, 0xC5, 0x96, 0x9C, 0xB1, 0xD3, 0x72, 0x93, 0xDF, 0x0C, 0x46, 0x0B, 0x3D, 0x43, 0x25, 0xCF, 0x0A, 0x34, 0x98, 0xD8, 0x8E, 0xD3, 0x73, 0xBC, 0xEB, 0x6A, 0x4F, 0xA4, 0x5C, 0x92, 0x73, 0x72, 0x5A, 0x2D, 0xF2,
0x94, 0xDA, 0x25, 0x44, 0xAE, 0xFF, 0x08, 0x6A, 0xBF, 0x6D, 0x87, 0x2B, 0x74, 0x8D, 0xCD, 0x12, 0xC5, 0x06, 0xF6, 0xB8, 0x5D, 0x47, 0x95, 0x4C, 0x89, 0x55, 0xAB, 0x62, 0xBB, 0x84, 0xE5, 0xFA, 0x8F, 0xC0, 0xF6, 0xBF, 0xAD, 0x6B, 0x51, 0x54, 0x63, 0xB5, 0x8E, 0x62, 0x05, 0x79, 0x5C, 0xAF, 0xA2, 0x5A, 0xA2, 0x24,
0x82, 0xC5, 0xC3, 0x9E, 0x95, 0x1D, 0x9A, 0xB3, 0x0D, 0x86, 0x9E, 0xF1, 0xC0, 0xC8, 0x27, 0x8E, 0x81, 0x15, 0xFC, 0x46, 0x33, 0x14, 0xA5, 0xC3, 0x37, 0xB9, 0x3C, 0xC1, 0xF2, 0x61, 0xCF, 0xB5, 0x8D, 0x70, 0xEC, 0x0A, 0x43, 0xCF, 0x64, 0x60, 0xE4, 0x33, 0x07, 0xE3, 0x8B, 0x2B, 0x4D, 0x3F, 0x5C, 0x23, 0x42, 0x51,
0x79, 0x15, 0x4E, 0xA8, 0xE8, 0xBE, 0x9E, 0xD9, 0xA5, 0x2E, 0xAB, 0x1D, 0xF2, 0x63, 0xB5, 0xDA, 0xAC, 0x4B, 0xCA, 0xFD, 0xA4, 0x67, 0xA8, 0x81, 0x6A, 0x44, 0x39, 0x7C, 0x53, 0x8B, 0xD7, 0x69, 0x09, 0x27, 0xDD, 0xE7, 0x13, 0x5D, 0xEA, 0x0B, 0xDF, 0xA1, 0xD8, 0x56, 0xEB, 0xC5, 0xBA, 0xC2, 0xDD, 0x4F, 0x6B, 0x86,
0x74, 0x11, 0xB4, 0xA7, 0x3E, 0x59, 0x57, 0x60, 0xA6, 0xCD, 0xFF, 0x9E, 0xB2, 0xF9, 0xE3, 0xCD, 0xA7, 0x4A, 0x68, 0x02, 0xE0, 0x56, 0xD4, 0x1D, 0x06, 0x15, 0x3E, 0x53, 0x03, 0x8B, 0x1E, 0x19, 0xED, 0xA9, 0xCF, 0x6E, 0x6B, 0x34, 0xA6, 0x2B, 0x7F, 0x4F, 0x45, 0xFC, 0x78, 0xF5, 0x50, 0x09, 0xEF, 0x00, 0xA4, 0x14,
0xBA, 0xCE, 0xEF, 0xB2, 0x8A, 0x3D, 0x46, 0xB3, 0xA3, 0xBA, 0x5E, 0x21, 0xDC, 0x14, 0xA4, 0x50, 0xB5, 0xA9, 0x8A, 0xEC, 0xAB, 0x1E, 0xCF, 0x93, 0x49, 0x98, 0xF5, 0x8F, 0x83, 0x1A, 0x55, 0x17, 0x57, 0x59, 0x47, 0x1E, 0xE3, 0xE8, 0x68, 0xAB, 0x55, 0xC3, 0xDC, 0x94, 0x74, 0xA1, 0x7A, 0x51, 0x8D, 0x7A, 0x5F, 0xFD,
0xB3, 0xF8, 0x43, 0xEB, 0xD4, 0xC3, 0xE2, 0xE8, 0xD6, 0x91, 0x66, 0x53, 0x4A, 0x23, 0x47, 0x34, 0x89, 0x99, 0x6F, 0x7D, 0x4A, 0xCC, 0x18, 0x3D, 0x6B, 0x23, 0x78, 0x9E, 0x4D, 0x50, 0x50, 0x3F, 0x4E, 0x27, 0x3F, 0xF5, 0xA8, 0xDC, 0xBA, 0x45, 0x2C, 0xA2, 0x68, 0x4A, 0xA5, 0xE5, 0x88, 0x83, 0x98, 0xC5, 0xD2, 0xA7,
0xCF, 0x57, 0x89, 0x28, 0x9F, 0xA9, 0x9A, 0x01, 0x66, 0xCE, 0x53, 0x3E, 0xA8, 0x87, 0x7C, 0x68, 0x0E, 0x8E, 0x95, 0x6B, 0x2B, 0x05, 0xC0, 0x45, 0xA4, 0xE5, 0x85, 0x4C, 0xD6, 0xB3, 0x31, 0xF0, 0x62, 0x96, 0x44, 0xEE, 0x33, 0x67, 0x33, 0xF2, 0xCC, 0x65, 0x97, 0x0F, 0xF6, 0xB0, 0x0F, 0x9D, 0x01, 0xC8, 0xA4, 0xE9,
0xCE, 0x02, 0x66, 0x53, 0x56, 0xEE, 0x00, 0x59, 0x8E, 0x45, 0x4A, 0x45, 0x15, 0x7B, 0x65, 0x51, 0x84, 0xC9, 0xCE, 0x64, 0x15, 0x1A, 0xBB, 0x3D, 0x37, 0xA0, 0x30, 0x4A, 0x32, 0x97, 0x07, 0xD9, 0x0B, 0xA2, 0x80, 0xF9, 0x2E, 0xAB, 0x70, 0x80, 0xAC, 0xDA, 0x22, 0x2D, 0xA3, 0xCA, 0xB5, 0xB2, 0xCC, 0xC2, 0xE4, 0x23,
0xEC, 0x45, 0x73, 0x35, 0x00, 0xA3, 0x4A, 0x7F, 0x55, 0xCC, 0x5D, 0x9A, 0x63, 0xED, 0x1F, 0xF7, 0x4A, 0xBA, 0x34, 0x1D, 0x2F, 0xD8, 0x72, 0x02, 0x2C, 0x7F, 0x59, 0xE5, 0x21, 0xCF, 0xB9, 0x09, 0xB7, 0x97, 0xC4, 0x15, 0xAB, 0x0A, 0xB4, 0xFC, 0xAB, 0x23, 0xEE, 0x4A, 0x8C, 0xF5, 0xF0, 0x04, 0x66, 0xA6, 0xB4, 0xCA,
0xFE, 0x4B, 0x79, 0xA7, 0x52, 0xEA, 0x2E, 0xF4, 0xA9, 0x62, 0x77, 0x4C, 0xC9, 0xBC, 0xDF, 0x53, 0x46, 0xDA, 0xC2, 0x59, 0x4A, 0x3A, 0x83, 0x46, 0xD7, 0x2F, 0xB1, 0xE3, 0x05, 0x6B, 0x06, 0xC0, 0x8A, 0xE3, 0x5F, 0xDA, 0x3B, 0xB5, 0xBA, 0xEE, 0x52, 0x9D, 0x2A, 0x57, 0xC7, 0x0C, 0xCD, 0xE1, 0x14, 0x6B, 0xCD, 0x64,
0x4F, 0x35, 0x93, 0xA8, 0xC3, 0x68, 0x72, 0xA2, 0xAE, 0xCA, 0x54, 0x69, 0xA1, 0x1E, 0x66, 0xB6, 0x65, 0x91, 0xC2, 0xB9, 0x60, 0x1C, 0xF3, 0x56, 0x2C, 0x1E, 0x59, 0x94, 0x92, 0x47, 0xD0, 0xF8, 0xFC, 0x25, 0x26, 0x06, 0x61, 0x39, 0x74, 0x66, 0x34, 0x1D, 0xA8, 0xAB, 0x13, 0x2A, 0x2D, 0xE5, 0xC3, 0xCC, 0xB6, 0x2C,
0x90, 0x7E, 0xD5, 0xA4, 0xD4, 0x17, 0x71, 0x8A, 0xC2, 0xC7, 0x1A, 0xFA, 0x5F, 0xDA, 0x63, 0x78, 0xA2, 0xC9, 0x9B, 0x49, 0x4F, 0x96, 0x22, 0x85, 0xA4, 0x2A, 0x56, 0x1A, 0x0B, 0xA6, 0x31, 0x6F, 0x4D, 0xE7, 0x81, 0xF0, 0xD7, 0x05, 0xA5, 0x1E, 0x44, 0x29, 0x4A, 0x97, 0x35, 0xA0, 0xA6, 0x87, 0xD5, 0x18, 0xD9, 0xD1,
0x9D, 0x3B, 0x9A, 0x6B, 0x45, 0x91, 0x81, 0x1C, 0x10, 0x2A, 0x1B, 0xCD, 0x53, 0x54, 0xD1, 0x85, 0x94, 0x2E, 0x5F, 0x5B, 0xE2, 0xCB, 0x80, 0x9D, 0xBC, 0xD5, 0x14, 0x45, 0xD2, 0xD3, 0xAE, 0x48, 0x29, 0xAA, 0x5A, 0xE5, 0x8E, 0x63, 0xAD, 0x44, 0x32, 0xD0, 0x81, 0x72, 0xE5, 0xAD, 0x79, 0x06, 0x2B, 0x3E, 0x91, 0xD2,
0x95, 0x3B, 0x5C, 0x6A, 0xA3, 0x16, 0x90, 0xEE, 0x37, 0x57, 0x34, 0x7B, 0xAA, 0x8C, 0x0A, 0x88, 0x8C, 0x52, 0x8C, 0x78, 0xB8, 0x2A, 0x09, 0xB5, 0xA9, 0x73, 0x97, 0x73, 0x4B, 0x72, 0x1A, 0xB0, 0x57, 0x34, 0xBB, 0x72, 0x8F, 0x53, 0x6D, 0x5C, 0x02, 0xB2, 0xF5, 0x16, 0x92, 0x66, 0x4B, 0x9E, 0x51, 0x09, 0x92, 0x71,
0x9C, 0x1D, 0x48, 0x4F, 0xC3, 0x9D, 0x1D, 0xC4, 0x0F, 0xEE, 0x9D, 0xE1, 0x23, 0x71, 0xF2, 0x43, 0x73, 0xBC, 0x1F, 0xD3, 0x31, 0x82, 0xE0, 0x5C, 0xC7, 0x47, 0x17, 0x13, 0x2D, 0xAE, 0x4A, 0xE7, 0x5A, 0x55, 0x39, 0xCE, 0xF6, 0x95, 0xD5, 0x70, 0x67, 0xFB, 0xC9, 0xC2, 0xBD, 0x33, 0x5A, 0x12, 0xA7, 0x2E, 0x9A, 0x93,
0xBB, 0xF4, 0xE4, 0x33, 0x74, 0x67, 0x96, 0x7D, 0xAD, 0xD9, 0xD6, 0xB9, 0xEE, 0x78, 0x53, 0x2F, 0x75, 0x8F, 0xDE, 0x67, 0x5A, 0x86, 0x3C, 0x76, 0xAE, 0x27, 0xF5, 0x8C, 0x1D, 0x33, 0x08, 0xCE, 0x5B, 0xB4, 0xB4, 0x4B, 0x59, 0x77, 0xC7, 0xB3, 0x58, 0xF6, 0x95, 0x61, 0x5B, 0xE7, 0x2D, 0xC7, 0x9B, 0x7A, 0x99, 0x7B,
0xD6, 0x17, 0x75, 0xDA, 0x2A, 0xBE, 0xA4, 0x8F, 0x1E, 0x7C, 0xF7, 0xF8, 0xD1, 0xA3, 0xE3, 0x1F, 0x1E, 0xB8, 0xE3, 0x60, 0xC1, 0xFF, 0xFF, 0x0B, 0x5B, 0x8E, 0xFC, 0xBE, 0xE0, 0x32, 0xFA, 0xB1, 0xF3, 0x56, 0x6A, 0x7E, 0xB1, 0xC5, 0x4B, 0x25, 0x49, 0xAD, 0xE1, 0xCE, 0x97, 0xCF, 0x9E, 0x3C, 0x39, 0xF9, 0xEB, 0x8E,
0xFD, 0xF9, 0xFD, 0xE0, 0x78, 0x08, 0xC3, 0x3D, 0x12, 0x86, 0x60, 0x7A, 0xC1, 0xD9, 0x01, 0x45, 0x9A, 0x22, 0xE4, 0x00, 0x28, 0xC9, 0xA1, 0x8D, 0x97, 0x3B, 0x3B, 0x0A, 0x16, 0xF2, 0xFB, 0x47, 0x31, 0x1D, 0x2B, 0xD6, 0xF4, 0xA1, 0x6B, 0x0B, 0x43, 0x88, 0x5E, 0x70, 0xB6, 0xCF, 0x81, 0x66, 0x10, 0xD9, 0x07, 0x26,
0x2A, 0xF2, 0x04, 0x48, 0x00, 0x19, 0x7C, 0x6C, 0xF8, 0x0A, 0x10, 0x0A, 0xC6, 0x8A, 0x69, 0x1A, 0x4A, 0x74, 0xAA, 0x93, 0xB1, 0x77, 0x93, 0xE6, 0x80, 0x32, 0x05, 0xB8, 0x49, 0x77, 0x47, 0x87, 0x5E, 0x94, 0x25, 0x40, 0x0F, 0x3E, 0x32, 0x7D, 0x4D, 0x16, 0x9E, 0x4D, 0x38, 0xD3, 0xDC, 0x94, 0xB4, 0x38, 0x4F, 0x46,
0xC5, 0x15, 0xC6, 0xA1, 0x88, 0x95, 0x87, 0x10, 0x9A, 0xD1, 0xE6, 0xB8, 0xB8, 0x0A, 0x30, 0x4A, 0xA0, 0x84, 0x0A, 0x10, 0xF8, 0xC6, 0x74, 0x3E, 0x0B, 0xDD, 0xDE, 0x4D, 0xB6, 0x05, 0xBC, 0x51, 0x92, 0x61, 0x32, 0x17, 0xB3, 0x8A, 0x00, 0xA2, 0x18, 0x2F, 0x4E, 0x93, 0xAB, 0xC8, 0xA3, 0xCD, 0x94, 0x62, 0x01, 0x65,
0xEB, 0x42, 0x29, 0xAE, 0x17, 0xB2, 0x50, 0x99, 0xD3, 0x55, 0x82, 0x55, 0xDE, 0x46, 0x5A, 0x36, 0x64, 0x5C, 0x80, 0x68, 0x3B, 0x14, 0x3B, 0xBB, 0x56, 0x8C, 0xBE, 0x19, 0x3B, 0x58, 0x7F, 0x20, 0x12, 0x50, 0x95, 0x60, 0x8A, 0xEB, 0x85, 0xC2, 0x54, 0x16, 0x54, 0x95, 0x6A, 0xAA, 0x2C, 0xA3, 0x4C, 0x1B, 0x8A, 0x56,
0x89, 0x62, 0x93, 0xF4, 0x2A, 0x1A, 0xEB, 0xA3, 0x0F, 0x17, 0xAF, 0xFF, 0xAE, 0xBD, 0x79, 0xF9, 0xA7, 0x52, 0x43, 0x65, 0x44, 0x61, 0x8C, 0xAE, 0xD0, 0x33, 0x80, 0xB4, 0x3D, 0x0E, 0x5D, 0xA4, 0x95, 0x43, 0xCA, 0xF2, 0x35, 0x2A, 0xDC, 0x1A, 0x7E, 0x78, 0xF5, 0xEE, 0x7F, 0x8D, 0xF7, 0x6F, 0x7F, 0xD7, 0x72, 0xA8,
0x6D, 0xC6, 0xF4, 0x21, 0x64, 0xA2, 0x73, 0xCD, 0x50, 0x0C, 0x98, 0xED, 0x1D, 0xE2, 0x4E, 0xC3, 0xD9, 0xB9, 0xDE, 0xD7, 0xF1, 0x91, 0x16, 0x71, 0x36, 0xD0, 0x0A, 0x29, 0xB2, 0xD1, 0x35, 0x6A, 0x56, 0xF8, 0x11, 0xD1, 0xA4, 0x25, 0x39, 0xC3, 0x21, 0x50, 0x6F, 0xEF, 0x30, 0x77, 0x8A, 0xF5, 0xA3, 0xAD, 0x43, 0xFC,
0x35, 0x8C, 0xDF, 0xF4, 0xE0, 0xDA, 0x70, 0x96, 0x78, 0xD4, 0xAB, 0xC2, 0x6B, 0xD6, 0xB4, 0x94, 0x60, 0x3C, 0xB0, 0x44, 0x32, 0x96, 0x02, 0x71, 0x52, 0xCA, 0x33, 0x6F, 0xA2, 0x7F, 0x83, 0x96, 0x41, 0xF6, 0x9B, 0x5F, 0x5C, 0x99, 0xCE, 0x92, 0xAE, 0x0E, 0xEA, 0xB4, 0x35, 0x2F, 0x5A, 0xDA, 0x6C, 0xD2, 0xB0, 0xC4,
0xFA, 0xE8, 0x8A, 0x84, 0x67, 0x07, 0xEC, 0x56, 0x89, 0xD6, 0x8A, 0xFB, 0x06, 0x4F, 0x66, 0xE6, 0x50, 0x64, 0x42, 0x45, 0x8A, 0x9F, 0xF8, 0xC6, 0x9C, 0xA0, 0x34, 0x56, 0x0C, 0x71, 0x9A, 0xCA, 0xAD, 0xE1, 0x25, 0x0B, 0xCF, 0xF6, 0xC5, 0xAD, 0x0A, 0xAE, 0x95, 0xD7, 0x0D, 0x4D, 0x16, 0xE2, 0x50, 0x26, 0x42, 0x65,
0x54, 0x2A, 0x69, 0x5E, 0xD6, 0x7A, 0xD4, 0x52, 0x1F, 0xBD, 0x23, 0xB4, 0x20, 0x02, 0x32, 0x2A, 0x29, 0xFE, 0x8C, 0xD7, 0xA8, 0x89, 0xFE, 0x23, 0x7B, 0xE6, 0x8C, 0x9F, 0xF8, 0x58, 0x82, 0x4B, 0x54, 0xA9, 0xC5, 0x79, 0x95, 0xEB, 0x71, 0xC9, 0xD6, 0xF0, 0x07, 0xC6, 0x1D, 0x22, 0xA0, 0x51, 0x8B, 0xF1, 0x90, 0x69,
0x6B, 0x52, 0x1D, 0x83, 0x99, 0x79, 0x05, 0xB9, 0xDF, 0xEF, 0x74, 0xB4, 0xC1, 0x9B, 0xB7, 0x5A, 0xA7, 0x53, 0x01, 0xD8, 0x5B, 0x50, 0x77, 0xE2, 0xFA, 0xEF, 0xEE, 0xA3, 0xA6, 0xEA, 0x8F, 0xE5, 0x59, 0xCE, 0x49, 0xF5, 0x68, 0x36, 0x0C, 0x84, 0xAB, 0x41, 0xF7, 0x47, 0xBD, 0x9E, 0x31, 0x78, 0xFF, 0xBD, 0xD1, 0xEB,
0x1F, 0xE9, 0xA3, 0x5F, 0x3F, 0xBC, 0x78, 0xDA, 0x84, 0xBA, 0xB0, 0x77, 0xD3, 0x1F, 0xF4, 0x7A, 0xAD, 0xB3, 0x03, 0x06, 0x52, 0x1F, 0xD7, 0x10, 0xF4, 0x4A, 0xD5, 0xC8, 0xEC, 0x2D, 0xB8, 0x3A, 0x49, 0xFE, 0x1F, 0x3E, 0x6E, 0x0D, 0x7F, 0xFA, 0xF0, 0xE6, 0x45, 0x07, 0x7E, 0xE1, 0xC1, 0xCD, 0xE1, 0xE0, 0xE0, 0x60,
0x71, 0x0D, 0x4E, 0x00, 0x57, 0x6F, 0x30, 0xDC, 0x02, 0xD7, 0xA1, 0x3E, 0x7A, 0xF9, 0x9C, 0x61, 0x7A, 0x34, 0xD8, 0x86, 0xA8, 0x01, 0x78, 0x25, 0xD2, 0x04, 0xF7, 0x6C, 0x5F, 0x64, 0x69, 0x0E, 0xEB, 0x18, 0x7C, 0xE5, 0xB0, 0x06, 0x4F, 0x01, 0xEB, 0x60, 0x70, 0xBC, 0x06, 0xAC, 0xA3, 0xD6, 0xF0, 0xED, 0x6B, 0x01,
0xE4, 0xDC, 0x3C, 0x3A, 0x3E, 0xD9, 0x02, 0x53, 0x1F, 0xD8, 0x7B, 0x0F, 0xA8, 0x4E, 0x40, 0x52, 0xC7, 0x5B, 0x09, 0x0A, 0x9C, 0x0E, 0x11, 0x41, 0x4C, 0xBF, 0xE9, 0xC9, 0x60, 0x1D, 0xA4, 0x06, 0xD0, 0x4A, 0xC2, 0x09, 0xE8, 0xDC, 0x3C, 0x39, 0x79, 0xBA, 0x06, 0x24, 0x2C, 0xB9, 0xBE, 0xFC, 0x19, 0xA0, 0xB0, 0xC6,
0x19, 0x9E, 0x6C, 0x81, 0xE8, 0x31, 0x08, 0x09, 0x11, 0x01, 0x92, 0x9B, 0xC3, 0x6D, 0xA4, 0x74, 0xA2, 0x8F, 0x2E, 0x5E, 0xFD, 0xD8, 0x1C, 0x02, 0x67, 0x83, 0xEE, 0x06, 0xD4, 0x5A, 0x03, 0x12, 0x94, 0x8E, 0x00, 0xC1, 0xA6, 0xDF, 0x1C, 0x3F, 0x5D, 0x03, 0xD0, 0x33, 0x10, 0x89, 0x00, 0x01, 0xC8, 0xCD, 0xD1, 0x3A,
0xC7, 0xC7, 0x75, 0xF0, 0x80, 0xED, 0x25, 0x51, 0x3D, 0xD2, 0x47, 0x40, 0x0A, 0x92, 0x23, 0xB0, 0x80, 0x59, 0x32, 0x1B, 0xFD, 0xD5, 0x0D, 0x96, 0x0B, 0x7C, 0x54, 0xC2, 0xCA, 0xF4, 0x57, 0xDF, 0x7C, 0xDD, 0x39, 0x46, 0xCB, 0x06, 0xCF, 0x4E, 0x9A, 0xC0, 0x81, 0xEC, 0xA5, 0x41, 0x3D, 0x69, 0x0D, 0x81, 0x0A, 0xA1,
0xD0, 0x9D, 0x58, 0x1A, 0x34, 0xF0, 0xAE, 0x69, 0x56, 0xDB, 0xC0, 0x6A, 0x8F, 0xF5, 0xD1, 0x3F, 0x90, 0x6F, 0xEC, 0x68, 0x30, 0xDC, 0x82, 0x6F, 0xB0, 0x7E, 0x13, 0x41, 0x81, 0x58, 0x0A, 0x19, 0xFD, 0xC9, 0x0D, 0x10, 0xAD, 0xC2, 0x42, 0x77, 0xCC, 0xC9, 0xA2, 0x80, 0x77, 0xC5, 0x7B, 0xB5, 0x15, 0xA4, 0xF6, 0xA4,
0x68, 0x8F, 0x38, 0x36, 0x46, 0x01, 0x46, 0xFF, 0x92, 0x12, 0x83, 0x88, 0xFA, 0x8F, 0x6A, 0x09, 0x2F, 0x89, 0x09, 0x4C, 0xFE, 0x1F, 0xA8, 0x05, 0x40, 0x72, 0x35, 0xFC, 0x1B, 0xB5, 0x9B, 0x2A, 0x1A, 0x1C, 0xAF, 0xD1, 0x6E, 0x48, 0x3F, 0xCA, 0x13, 0x8C, 0x95, 0x41, 0x40, 0xE8, 0xDF, 0x72, 0x64, 0x08, 0xD0, 0xE1,
0xD3, 0x1F, 0x6E, 0xE1, 0x3C, 0x60, 0xF2, 0xE0, 0x38, 0xE0, 0xCD, 0x27, 0x9B, 0x9B, 0x28, 0xD0, 0x42, 0xB9, 0x82, 0xB8, 0x80, 0x61, 0x61, 0x73, 0x62, 0xC0, 0x93, 0x46, 0xC4, 0x4B, 0x43, 0x82, 0xC8, 0xFF, 0x8D, 0xB8, 0x00, 0x20, 0x37, 0x87, 0xC7, 0x6B, 0x28, 0x0F, 0x44, 0x1E, 0x8A, 0x03, 0x6D, 0x7E, 0xBA, 0xBA,
0xD6, 0x1F, 0x1F, 0xDF, 0x3C, 0x3E, 0xAE, 0x86, 0x00, 0xE3, 0x39, 0xC6, 0xC6, 0xA2, 0x88, 0x5F, 0x9C, 0x10, 0x8A, 0x82, 0xFD, 0xBF, 0x97, 0x30, 0x84, 0x0B, 0x88, 0x02, 0x17, 0xDE, 0x2A, 0xD8, 0x05, 0x32, 0x0B, 0xAB, 0x23, 0x03, 0x59, 0x7F, 0x76, 0x72, 0xF3, 0xEC, 0xA4, 0x1E, 0x00, 0xB2, 0xE7, 0x64, 0x1B, 0xCB,
0xD7, 0xB5, 0x43, 0x3D, 0x6F, 0x07, 0x32, 0x61, 0x07, 0xD5, 0xA2, 0xBC, 0x44, 0x49, 0xF4, 0x34, 0x91, 0x3E, 0x1A, 0x56, 0xC8, 0xA6, 0x89, 0x72, 0x8B, 0xB6, 0x2C, 0x7E, 0x79, 0x87, 0x50, 0x66, 0xEC, 0xFF, 0xB5, 0xC4, 0x10, 0x2E, 0xBC, 0x6D, 0x6C, 0xEA, 0x65, 0x39, 0xD0, 0x44, 0x5C, 0xD4, 0xB3, 0xF2, 0x0A, 0x26,
0x4D, 0xD0, 0x4F, 0x53, 0x3C, 0x5A, 0x1E, 0x26, 0x77, 0xF0, 0x86, 0x43, 0x5D, 0x8A, 0x2C, 0x1B, 0xA5, 0x11, 0x05, 0xAD, 0xC6, 0x8D, 0x3E, 0x3A, 0x3E, 0x2C, 0xF1, 0x6A, 0xA2, 0xD6, 0xF0, 0xB8, 0x46, 0x6F, 0x9A, 0x72, 0xB7, 0x78, 0xD9, 0x14, 0xFE, 0xBC, 0x8B, 0x27, 0xC9, 0xA3, 0xCE, 0x1D, 0xDA, 0x70, 0x14, 0x77,
0x4D, 0xBF, 0x9B, 0x2B, 0x63, 0x4C, 0x27, 0x0B, 0x5C, 0x12, 0x04, 0xB5, 0xF5, 0x11, 0x37, 0xD5, 0x47, 0xCF, 0xA2, 0xE3, 0x6D, 0xB4, 0xD2, 0x19, 0x6C, 0xA1, 0xE7, 0xB0, 0x2C, 0x2B, 0x75, 0x23, 0x1A, 0x5C, 0xCD, 0x9B, 0xD6, 0xF0, 0xE4, 0xA8, 0xB2, 0xFB, 0x5D, 0x9D, 0x19, 0x23, 0x1E, 0x2C, 0x70, 0x59, 0x10, 0x34,
0x16, 0x89, 0x1C, 0xA6, 0x99, 0xCE, 0x80, 0xAB, 0x26, 0x2E, 0xB4, 0xEE, 0x56, 0x31, 0x65, 0xD4, 0x6E, 0xA3, 0x17, 0x1C, 0x2C, 0xF8, 0x46, 0x10, 0xD6, 0xD6, 0xE6, 0x47, 0x52, 0xB4, 0x35, 0x7C, 0x19, 0x5F, 0xAF, 0xC3, 0x95, 0xDE, 0x60, 0x0D, 0xB6, 0x28, 0xE8, 0x08, 0xCE, 0xF4, 0xE0, 0x60, 0x71, 0xD6, 0x24, 0x8E,
0x8A, 0x68, 0x08, 0xB9, 0x84, 0x1F, 0xED, 0x4D, 0x23, 0x11, 0x29, 0xDF, 0x80, 0x3E, 0x02, 0x23, 0x5C, 0xB2, 0xE7, 0xB6, 0x6A, 0x6B, 0x24, 0x6E, 0x0A, 0xA5, 0xD6, 0xFD, 0x32, 0xA6, 0x0A, 0xDB, 0x75, 0xF8, 0x42, 0x83, 0x05, 0xDF, 0x0C, 0xA2, 0xB4, 0xFA, 0x5C, 0x89, 0x0A, 0xA2, 0x2F, 0x91, 0x57, 0x5B, 0xE3, 0x48,
0x4B, 0x74, 0xBC, 0x37, 0xAD, 0x48, 0xE4, 0x7C, 0x0B, 0x7A, 0x59, 0x10, 0xD3, 0x36, 0x9C, 0x8F, 0x64, 0x32, 0x81, 0x84, 0x55, 0x5F, 0x37, 0x89, 0xE6, 0xA0, 0x8C, 0xCA, 0x9F, 0x80, 0x1F, 0x81, 0x19, 0x2E, 0xC5, 0xBA, 0xAD, 0xC6, 0x1C, 0x49, 0x8A, 0xC2, 0x75, 0x89, 0xAF, 0xB7, 0xC6, 0x15, 0x05, 0x9D, 0x3F, 0x03,
0x1F, 0x76, 0xAE, 0x5D, 0xD2, 0xF3, 0xDA, 0xE3, 0x88, 0x14, 0xBA, 0xCD, 0x07, 0x13, 0xE9, 0xEC, 0xCD, 0x27, 0xD4, 0x09, 0x1D, 0xBE, 0xB1, 0x23, 0x7D, 0xF4, 0x5F, 0x16, 0x6C, 0x8C, 0xBD, 0x71, 0x1F, 0xD9, 0x64, 0x82, 0x0E, 0xAB, 0x39, 0x6F, 0x52, 0xC5, 0xC1, 0x1F, 0xF1, 0xDF, 0xB8, 0xE0, 0xFF, 0x1B, 0x8F, 0x23,
0x93, 0x17, 0xD1, 0xB9, 0x79, 0x81, 0xF1, 0x13, 0x99, 0xD2, 0xF9, 0xEA, 0x6D, 0xEA, 0x9C, 0x17, 0xBE, 0xB1, 0xA6, 0x1B, 0x22, 0xB7, 0xA9, 0xBA, 0xDE, 0x41, 0x32, 0xE0, 0x56, 0x1F, 0x4C, 0x64, 0x7B, 0x6F, 0x19, 0x50, 0xA7, 0x21, 0x7D, 0x74, 0xD5, 0x1A, 0x7E, 0xEB, 0xC5, 0x78, 0xAE, 0xEE, 0x60, 0x7C, 0xCB, 0xA6,
0x3D, 0xFA, 0x8B, 0xED, 0x6E, 0xCE, 0xCC, 0x10, 0x09, 0x21, 0xC4, 0xDD, 0x0E, 0x0B, 0x14, 0xA3, 0xCF, 0xE0, 0x60, 0x3B, 0x24, 0xC7, 0x38, 0xB6, 0x5E, 0xD8, 0x3C, 0x5E, 0xBD, 0x8E, 0x9F, 0xF3, 0xC6, 0x37, 0x6F, 0xF9, 0x86, 0xC8, 0x75, 0xBC, 0xAE, 0x1F, 0xE0, 0x8F, 0xFE, 0x88, 0x58, 0xDB, 0x3A, 0x3E, 0xE0, 0x1B,
0xC6, 0xD7, 0x50, 0x6E, 0x19, 0xAB, 0x71, 0x6D, 0xB7, 0x80, 0x36, 0xFA, 0xE8, 0xE9, 0x6F, 0xCF, 0x6A, 0x07, 0x29, 0xB6, 0xEA, 0x5B, 0xC5, 0xC2, 0xE3, 0xB9, 0x1F, 0xCB, 0xEB, 0xD7, 0x83, 0x02, 0x67, 0xF4, 0x25, 0x2E, 0xD6, 0x03, 0x02, 0xD7, 0xF8, 0x92, 0x2D, 0x6C, 0xF3, 0x73, 0x70, 0xB7, 0xCC, 0xEB, 0x51, 0x63,
0x13, 0xEC, 0x2C, 0x33, 0xA9, 0xA5, 0xF6, 0x9C, 0xAA, 0x13, 0x5B, 0x0A, 0xBE, 0x04, 0x81, 0x74, 0x91, 0x4C, 0x97, 0xD8, 0xAC, 0xC6, 0xE3, 0x97, 0x8B, 0x60, 0xB5, 0x40, 0x99, 0xD6, 0xF0, 0xC5, 0x2F, 0x2F, 0x1B, 0x1B, 0x29, 0x31, 0xEB, 0x5B, 0x47, 0xC2, 0x93, 0xD8, 0x09, 0x55, 0x96, 0x0B, 0x6A, 0xE9, 0x35, 0xA7,
0x40, 0xC4, 0xC7, 0xA9, 0x61, 0xD7, 0xCF, 0x2B, 0xA2, 0x21, 0xD5, 0x94, 0xF6, 0x02, 0x8E, 0x76, 0xA5, 0x2E, 0xD6, 0xED, 0xDE, 0x74, 0xC6, 0xB9, 0xDE, 0xB7, 0x6E, 0x60, 0x4B, 0xD3, 0xAE, 0x08, 0x41, 0x3E, 0x49, 0xD6, 0x52, 0x9A, 0x59, 0xAF, 0x8D, 0x0F, 0x67, 0xC1, 0x80, 0xC4, 0xC7, 0x29, 0x42, 0x9A, 0xAB, 0x30,
0xE2, 0x80, 0x90, 0xB9, 0x67, 0xD5, 0x9F, 0xB2, 0xE2, 0xED, 0xF4, 0x11, 0x68, 0xED, 0x0D, 0x1C, 0xD4, 0xCE, 0x32, 0x02, 0xC1, 0x17, 0x4E, 0x2F, 0x4F, 0x97, 0x89, 0x17, 0xE4, 0x9C, 0x32, 0xDE, 0xE0, 0x6A, 0x53, 0xEC, 0x12, 0xD5, 0x6E, 0x8D, 0x67, 0xB2, 0xD5, 0xDB, 0x66, 0x1C, 0x10, 0x99, 0x7B, 0x56, 0xF3, 0x90,
0xA1, 0xB7, 0x4D, 0x66, 0xB9, 0x5A, 0xBA, 0xEE, 0x7A, 0x9B, 0xB4, 0x72, 0xE1, 0x78, 0x4B, 0x6B, 0x73, 0x0C, 0x90, 0x53, 0x7E, 0x9E, 0x4C, 0x6C, 0x73, 0xF3, 0x95, 0x2C, 0xD7, 0x1A, 0x82, 0x6B, 0xEF, 0x71, 0xD1, 0xB8, 0x97, 0x89, 0x00, 0x3C, 0x70, 0xF7, 0xF2, 0x02, 0x3B, 0xE5, 0xD6, 0xE9, 0x59, 0x2E, 0xB1, 0x3E,
0xAC, 0x84, 0xB3, 0x0A, 0xDE, 0xBC, 0x62, 0xFB, 0x2F, 0x1C, 0xC5, 0x89, 0x59, 0x3F, 0x40, 0x10, 0x13, 0xB4, 0x78, 0x79, 0xA1, 0x5D, 0x5D, 0xFE, 0x74, 0xF5, 0x13, 0x83, 0xB4, 0xD5, 0xBB, 0x95, 0x57, 0x8E, 0xB7, 0xB4, 0x56, 0x87, 0x80, 0x3E, 0xE5, 0xBB, 0xC9, 0x04, 0x5B, 0xF7, 0xD7, 0x8A, 0x2A, 0x78, 0xF3, 0x9A,
0xF3, 0xBB, 0xDD, 0x44, 0x07, 0xE8, 0x73, 0x4F, 0x81, 0x01, 0xB9, 0xDD, 0x77, 0x4C, 0x00, 0x22, 0x06, 0x9B, 0xE8, 0x69, 0xC0, 0x14, 0xF5, 0xFC, 0xEA, 0xED, 0xE5, 0x1F, 0xD8, 0x8A, 0xB3, 0x71, 0x73, 0x03, 0xC1, 0xC6, 0xE0, 0xE2, 0xC5, 0x2B, 0xE3, 0xF2, 0xE2, 0xDB, 0xCB, 0xEF, 0x7E, 0xD8, 0x8C, 0x75, 0x40, 0x9D,
0xAE, 0xB4, 0x34, 0xD8, 0x9F, 0x9A, 0x06, 0x5F, 0x83, 0x9E, 0x3E, 0x3A, 0xE4, 0x9A, 0x38, 0x1B, 0xE8, 0x8A, 0x35, 0x44, 0x7D, 0x69, 0xAF, 0xF1, 0x68, 0x6F, 0x5B, 0x32, 0x0C, 0xD4, 0xDA, 0xAD, 0x1B, 0x73, 0x36, 0x1E, 0xAC, 0xC2, 0x27, 0x48, 0x3B, 0x31, 0xEA, 0xF5, 0xE5, 0xF7, 0x9B, 0xE2, 0x12, 0x9C, 0xFD, 0x6D,
0x03, 0xB9, 0x88, 0x94, 0x6F, 0x60, 0x18, 0x07, 0x56, 0xF1, 0x91, 0x12, 0xBD, 0x89, 0xF3, 0xB0, 0x96, 0xFA, 0xE8, 0xF2, 0x66, 0xE1, 0x05, 0x4B, 0xBF, 0x62, 0xB1, 0x09, 0x8D, 0xDD, 0x3E, 0x9F, 0x3E, 0x3A, 0xEC, 0x8A, 0x39, 0x2B, 0xF0, 0x4A, 0x14, 0x24, 0x7E, 0x19, 0xEF, 0xE8, 0x6A, 0x6B, 0x03, 0xB9, 0x18, 0x95,
0x42, 0x55, 0x6B, 0xA4, 0xB7, 0x95, 0x42, 0x04, 0x29, 0x4C, 0x23, 0x3D, 0xAE, 0x10, 0x5C, 0xD0, 0x91, 0xD6, 0xFA, 0x86, 0x77, 0xAA, 0x15, 0x44, 0xFE, 0x25, 0x3F, 0xC1, 0x30, 0x0E, 0x52, 0xF1, 0x91, 0x23, 0xBD, 0x8A, 0xF2, 0x88, 0x92, 0xAD, 0xE1, 0xC5, 0x0D, 0x56, 0xC7, 0x60, 0xD3, 0xF6, 0x3A, 0x1C, 0x41, 0x08,
0x15, 0x33, 0xDD, 0x20, 0xEF, 0x4C, 0x31, 0xEF, 0xBC, 0xB8, 0xD8, 0x4D, 0x28, 0x9B, 0xEE, 0x2D, 0xE1, 0x4C, 0xF7, 0x9A, 0x70, 0x34, 0xBE, 0xDE, 0x2E, 0xA4, 0x7A, 0x0D, 0x86, 0x44, 0xA8, 0x08, 0x8E, 0x80, 0xFC, 0x9C, 0x21, 0x34, 0xA1, 0xA3, 0xCC, 0xF5, 0x21, 0x62, 0x78, 0x8F, 0x5C, 0x21, 0xE0, 0x0F, 0xC9, 0x98,
0xB0, 0xE1, 0x20, 0x82, 0x37, 0x84, 0xB1, 0xF3, 0x26, 0x03, 0x08, 0xC9, 0x73, 0xFA, 0x37, 0xDB, 0xB8, 0x8E, 0x20, 0x23, 0xE9, 0x39, 0x87, 0xB1, 0xDF, 0x1C, 0xE9, 0x0A, 0xFD, 0xCE, 0x94, 0xFA, 0x9D, 0x37, 0xAF, 0x36, 0x63, 0xCA, 0x50, 0xD9, 0x96, 0x2C, 0x19, 0x35, 0x73, 0x7B, 0x86, 0xCC, 0x90, 0xF3, 0xED, 0x11,
0xDD, 0xA9, 0xD7, 0x1C, 0x96, 0x52, 0xBB, 0x8D, 0xD3, 0x20, 0x27, 0x26, 0xB1, 0x1D, 0xDC, 0x76, 0x5D, 0x57, 0x21, 0x52, 0x5B, 0xA6, 0x13, 0xED, 0x82, 0x9D, 0x15, 0x56, 0x1C, 0x44, 0xC8, 0x82, 0x18, 0x3B, 0xAF, 0x32, 0x80, 0x50, 0x34, 0xE7, 0xF0, 0x66, 0x1D, 0xD5, 0x89, 0xD0, 0x48, 0x6B, 0xCE, 0x51, 0xA2, 0x37,
0x6D, 0xA3, 0x9B, 0xC1, 0x36, 0xBA, 0x91, 0x29, 0x4A, 0xAA, 0xE7, 0xF8, 0x0B, 0x65, 0x1A, 0x5C, 0x37, 0xFB, 0x92, 0x6B, 0x1E, 0x8B, 0xFA, 0x31, 0x0D, 0xDA, 0x8F, 0xEF, 0x55, 0x6B, 0x8E, 0x2A, 0xB1, 0x5D, 0x47, 0x69, 0xA8, 0x25, 0x63, 0x66, 0x63, 0xE6, 0x7D, 0xDA, 0x98, 0x21, 0x4A, 0x59, 0xC1, 0x13, 0xE3, 0x95,
0xE8, 0xA3, 0x67, 0x6F, 0x77, 0x13, 0xD3, 0xB0, 0xB3, 0x8A, 0x31, 0x6D, 0xAB, 0x08, 0x46, 0x99, 0xDA, 0x77, 0x29, 0xB6, 0xDA, 0x40, 0x1B, 0x2B, 0x24, 0xFC, 0xF8, 0xB7, 0x0E, 0x6F, 0x06, 0xEB, 0xF0, 0x46, 0xC5, 0x28, 0xCD, 0x9E, 0x93, 0x07, 0xEA, 0x69, 0x68, 0xDE, 0xEC, 0x21, 0xE7, 0x3C, 0x16, 0xCD, 0x6D, 0x1A,
0xB7, 0x1D, 0x69, 0x63, 0x55, 0x5D, 0x1B, 0x77, 0x9C, 0x61, 0x56, 0x5F, 0x83, 0x7E, 0x7C, 0x63, 0xF5, 0x71, 0x3A, 0x37, 0x6A, 0xEB, 0x88, 0xB7, 0xD3, 0x47, 0xCA, 0x20, 0x30, 0xF4, 0xFD, 0x66, 0x6C, 0x1A, 0x55, 0x56, 0xD3, 0xA6, 0xAD, 0x65, 0xC1, 0x78, 0xA3, 0xB6, 0x3E, 0x8C, 0x5E, 0x81, 0x1B, 0x28, 0x83, 0xE1,
0xEF, 0x8C, 0x95, 0xF6, 0xE2, 0xCD, 0xD3, 0x9D, 0xE8, 0x4A, 0x74, 0xBA, 0x1F, 0x7D, 0x45, 0x2C, 0xEF, 0x5B, 0x67, 0x0E, 0x71, 0xEB, 0x3B, 0x15, 0x36, 0xD2, 0xF3, 0x86, 0xB8, 0x41, 0x95, 0x6D, 0xA7, 0x87, 0xE1, 0xCD, 0xDC, 0x36, 0x7F, 0x7C, 0xF3, 0xFA, 0xE3, 0x74, 0x6E, 0x36, 0xE6, 0x91, 0x2C, 0x87, 0xC0, 0xAE,
0x47, 0xAF, 0x89, 0x1B, 0x68, 0x17, 0x9E, 0xCF, 0x5F, 0x91, 0xB7, 0x13, 0xAD, 0xD1, 0x9E, 0xF7, 0xA3, 0x32, 0xC6, 0xF4, 0xBE, 0xF5, 0x35, 0x9B, 0xDB, 0xBE, 0x79, 0x6D, 0xBC, 0x79, 0xFF, 0x62, 0x23, 0xBC, 0x8A, 0x2A, 0xDD, 0x0E, 0xBF, 0xE2, 0x26, 0x6F, 0x9B, 0x67, 0x58, 0x6B, 0xD6, 0x5C, 0xA9, 0xA8, 0x50, 0x6B,
0xEF, 0xF9, 0xB5, 0x55, 0xC6, 0xDB, 0xE9, 0xA3, 0x97, 0x9D, 0x37, 0xF4, 0x68, 0x27, 0xEA, 0x12, 0xBD, 0xEE, 0x47, 0x63, 0x11, 0xCF, 0xFB, 0x56, 0xDA, 0xF5, 0xF8, 0x8E, 0xE1, 0x4C, 0x9C, 0x57, 0x9E, 0x2F, 0x8F, 0xC8, 0xDB, 0x08, 0xD7, 0x78, 0xCD, 0xDB, 0x61, 0x99, 0x68, 0xF4, 0xB6, 0xF9, 0x35, 0x9B, 0xDB, 0xBE,
0xC4, 0xB1, 0x17, 0xB5, 0x55, 0x46, 0x5B, 0xE9, 0xA3, 0xF7, 0x9D, 0x1F, 0xE1, 0xEF, 0x4E, 0xD4, 0xC5, 0x7A, 0xDC, 0x8F, 0xB2, 0x38, 0xB7, 0xFB, 0x56, 0x95, 0xEF, 0xF9, 0x8D, 0x59, 0x26, 0xCB, 0x21, 0x4C, 0xD5, 0x7B, 0xCF, 0xAF, 0x36, 0xC2, 0xAE, 0xA8, 0xD6, 0xED, 0x70, 0x2C, 0x6E, 0xF3, 0xB6, 0x99, 0x76, 0x35,
0x65, 0xAE, 0x6A, 0x2B, 0x0A, 0xDA, 0xE8, 0xA3, 0xE7, 0x17, 0xBF, 0x69, 0xCD, 0xE7, 0xDE, 0xCA, 0xC5, 0x87, 0x43, 0xB5, 0xCB, 0x9F, 0x5A, 0x3B, 0xD1, 0x18, 0x71, 0xEC, 0x45, 0x63, 0x96, 0xF1, 0x52, 0x58, 0x79, 0xD6, 0xFB, 0x1A, 0xBF, 0x1B, 0x61, 0x97, 0xA8, 0x71, 0x3B, 0xCC, 0x92, 0xAD, 0xDD, 0x36, 0xAB, 0xAC,
0x76, 0xBD, 0x1F, 0x7D, 0x51, 0xA6, 0xF7, 0xAD, 0x2D, 0xBA, 0x07, 0x68, 0x6C, 0xD4, 0x0F, 0x87, 0xA2, 0x21, 0x3E, 0xFB, 0x02, 0x47, 0xDA, 0x33, 0x63, 0x37, 0xF1, 0x75, 0x63, 0x46, 0xA1, 0x4C, 0x6B, 0xF8, 0xFA, 0xD5, 0x2F, 0x46, 0xE7, 0xB5, 0x77, 0x8D, 0x7D, 0x71, 0xBF, 0x33, 0xE3, 0xE2, 0x5B, 0xAC, 0xC0, 0xDA,
0x01, 0x31, 0xEA, 0x77, 0x17, 0x45, 0x7B, 0xCC, 0xE4, 0xBE, 0xF5, 0xE4, 0x10, 0xAB, 0x82, 0x8A, 0x92, 0x25, 0x86, 0xF5, 0x11, 0xB7, 0xD3, 0xE0, 0x36, 0xD3, 0x00, 0xC7, 0xA8, 0xEA, 0xED, 0xF0, 0x8B, 0x37, 0x7A, 0xDB, 0xDC, 0xE2, 0x7B, 0x80, 0xB0, 0x0C, 0x7E, 0x85, 0xB5, 0x2F, 0xA2, 0x20, 0xAD, 0x7D, 0xC1, 0x95,
0x35, 0xD4, 0x1A, 0x97, 0xCF, 0xB5, 0x57, 0xE2, 0xB4, 0x02, 0x37, 0x1B, 0xCF, 0xD9, 0xE5, 0x0D, 0x6D, 0x93, 0xF4, 0x24, 0x07, 0xB7, 0x83, 0xA3, 0xA3, 0xED, 0xF1, 0xD2, 0xDC, 0x8C, 0x41, 0x8C, 0xEB, 0xDD, 0x84, 0xD3, 0x9E, 0x34, 0x72, 0xFB, 0x5E, 0x86, 0x55, 0x83, 0x45, 0x69, 0x17, 0xC3, 0xFA, 0x48, 0xDB, 0x69,
0x86, 0xB7, 0x79, 0xD3, 0xA8, 0x47, 0x47, 0x5B, 0xEA, 0x44, 0xDE, 0x8C, 0xC1, 0xDF, 0x62, 0x58, 0xE6, 0x24, 0x7C, 0x53, 0x00, 0x1D, 0xCE, 0x93, 0xB0, 0x13, 0x68, 0x9B, 0x29, 0x16, 0xF2, 0xBD, 0xBB, 0x78, 0x6D, 0x7C, 0x13, 0xFD, 0xAD, 0xD1, 0x9A, 0x95, 0x63, 0x76, 0x45, 0x43, 0xDB, 0x34, 0x3E, 0xE9, 0xC1, 0xED,
0x84, 0xB6, 0xE3, 0xE8, 0xA3, 0x17, 0x24, 0xD4, 0xAE, 0xF0, 0xB0, 0xE2, 0x2E, 0x00, 0x09, 0x8B, 0xD8, 0x02, 0x14, 0xFA, 0xC4, 0x98, 0xEB, 0xA3, 0x2B, 0x7C, 0xE0, 0x31, 0x42, 0x0E, 0xEB, 0x0C, 0x6F, 0x8B, 0xC2, 0xA8, 0x8F, 0x1F, 0xAF, 0xC9, 0x13, 0x75, 0x33, 0x86, 0x3C, 0xC5, 0xB0, 0x4A, 0x49, 0xE4, 0xA6, 0x00,
0xBF, 0x23, 0xE0, 0xC2, 0xB3, 0x72, 0x64, 0x95, 0xF7, 0x0B, 0xD0, 0x0D, 0x42, 0xB8, 0xE3, 0x27, 0xF9, 0x3A, 0x56, 0x30, 0x7D, 0xB6, 0xFD, 0x6F, 0x74, 0x16, 0x3E, 0x9C, 0xC7, 0xF2, 0x7F, 0x9C, 0x4E, 0xE8, 0x20, 0x84, 0xFD, 0x86, 0x85, 0xC6, 0x25, 0x5D, 0xD6, 0xDC, 0x05, 0xA0, 0x40, 0x89, 0xB6, 0x00, 0xE1, 0xFC,
0x2C, 0x0C, 0x57, 0x80, 0xD1, 0xBD, 0x71, 0x2B, 0xBE, 0xD9, 0x69, 0xEC, 0x39, 0x16, 0x00, 0x3E, 0xB5, 0xAE, 0xF1, 0xD5, 0x34, 0x96, 0x76, 0x15, 0x6D, 0xDB, 0x50, 0x73, 0x8E, 0xB9, 0x3E, 0x3A, 0xDF, 0x11, 0xB0, 0xE8, 0x5F, 0x35, 0xB0, 0xDA, 0xFB, 0x05, 0xF8, 0x06, 0x21, 0xDA, 0xF1, 0x93, 0x3E, 0x8E, 0x15, 0xA2,
0xC1, 0x26, 0xE0, 0x3B, 0x02, 0x43, 0x89, 0xB0, 0x67, 0xBE, 0x40, 0xCF, 0x36, 0x58, 0xE1, 0xCB, 0x3C, 0x0A, 0xA4, 0x9D, 0xB3, 0xD3, 0xC8, 0x27, 0xD3, 0xC8, 0x2F, 0xB6, 0xFF, 0x0D, 0xCF, 0x70, 0x60, 0x85, 0x1B, 0x65, 0xE3, 0x7B, 0xE3, 0xAE, 0xE5, 0x66, 0xA7, 0x91, 0xE7, 0x58, 0xC8, 0xF8, 0xC2, 0xBA, 0xA2, 0xA3,
0x84, 0x54, 0x1B, 0xD0, 0x94, 0xFB, 0x8E, 0xDE, 0x91, 0xA9, 0x1D, 0x00, 0x8D, 0x1A, 0xE8, 0xE9, 0x80, 0xEE, 0xD5, 0x60, 0x1E, 0x52, 0x6D, 0x1F, 0x90, 0xDC, 0x69, 0x2C, 0x03, 0x7B, 0x1D, 0xE4, 0xB6, 0x1D, 0x2A, 0x02, 0xDD, 0x89, 0x20, 0x54, 0x10, 0x7B, 0xE6, 0x47, 0xE0, 0xC5, 0x06, 0x2B, 0x3A, 0xCC, 0xA3, 0x84,
0x25, 0xDF, 0xC5, 0xA8, 0xDC, 0xDD, 0x55, 0x2B, 0x85, 0xA4, 0xF7, 0x62, 0x25, 0x31, 0x96, 0x59, 0xE1, 0xFD, 0x4E, 0x67, 0x36, 0xC4, 0x5D, 0x27, 0x9A, 0x60, 0xDA, 0x05, 0x3B, 0x8D, 0x7C, 0x86, 0xD8, 0x49, 0xB4, 0xC3, 0x44, 0xB3, 0x01, 0x4D, 0xBB, 0xEF, 0xE8, 0x07, 0x36, 0xB5, 0x03, 0xE0, 0x68, 0x80, 0x4F, 0xFB,
0xED, 0xEC, 0x60, 0x36, 0x2C, 0x7B, 0xF4, 0xBC, 0x74, 0xCB, 0x10, 0x70, 0xBA, 0xF1, 0x8E, 0x21, 0x94, 0xD2, 0x08, 0xA8, 0x69, 0x6B, 0x6F, 0x8C, 0xE0, 0x73, 0x7C, 0xAF, 0x86, 0xD0, 0x90, 0x7A, 0xFB, 0x80, 0xD4, 0x2A, 0xE5, 0x2E, 0x46, 0xED, 0xEE, 0xAE, 0x46, 0x5D, 0x48, 0x76, 0x2F, 0x56, 0x1A, 0x62, 0x95, 0x14,
0x5B, 0x7B, 0x8F, 0x0E, 0xBF, 0xC3, 0x8D, 0x43, 0x48, 0xBB, 0x61, 0x59, 0x7E, 0xEE, 0xE6, 0xA1, 0x61, 0x62, 0xF3, 0xD0, 0xB1, 0xD8, 0x3C, 0x24, 0x4D, 0xBD, 0x62, 0xF9, 0xF9, 0xEC, 0x98, 0x76, 0x9D, 0x18, 0x51, 0xD3, 0xB0, 0xED, 0xEB, 0xB8, 0x6A, 0xE9, 0x79, 0xE5, 0x96, 0x21, 0xB4, 0x74, 0xE5, 0x1D, 0x43, 0x44,
0xDD, 0xF4, 0xFB, 0xFD, 0x2A, 0x9C, 0x57, 0xDC, 0x3F, 0x74, 0x27, 0x2C, 0xCD, 0x41, 0x98, 0x15, 0x59, 0x1A, 0x0A, 0x96, 0x86, 0x12, 0x4B, 0x27, 0x77, 0xB9, 0x25, 0x2C, 0x3D, 0x9A, 0x76, 0x8D, 0xF7, 0x66, 0xF0, 0xA9, 0x6B, 0xFC, 0x4C, 0x0A, 0xBF, 0xC1, 0x8D, 0x43, 0x84, 0x3B, 0xF6, 0x32, 0xC6, 0x5D, 0x47, 0x6E,
0x23, 0xEA, 0x4E, 0x38, 0xE2, 0x0B, 0x3B, 0x5F, 0x09, 0x4B, 0x95, 0x36, 0x79, 0x51, 0xDB, 0xBE, 0xAB, 0x3D, 0x5E, 0x14, 0x24, 0x1D, 0x0C, 0x8F, 0x0A, 0x63, 0xF3, 0x90, 0x58, 0x5F, 0x1C, 0xFD, 0x43, 0xC4, 0x4D, 0x6C, 0x1E, 0x52, 0x42, 0x6F, 0x37, 0x87, 0xB4, 0x29, 0xE2, 0xDE, 0xF6, 0x0F, 0xDD, 0x4B, 0x93, 0xE6,
0x21, 0x6D, 0xC2, 0x7C, 0xFE, 0xC5, 0x5D, 0xFA, 0xFC, 0x74, 0x0B, 0x9F, 0x9F, 0x66, 0x7C, 0x7E, 0x87, 0xCE, 0x2E, 0x08, 0xFF, 0xC6, 0x1C, 0x5E, 0xB0, 0x55, 0x20, 0x66, 0xCD, 0x26, 0xE1, 0x9F, 0x68, 0x12, 0x2E, 0xE2, 0x26, 0x3D, 0xBD, 0xCF, 0x1D, 0x51, 0xF7, 0xD2, 0x22, 0x39, 0xB1, 0xF3, 0x99, 0x34, 0xA9, 0xD6,
0xC3, 0xE9, 0x95, 0x6C, 0xED, 0xD6, 0x43, 0x22, 0x4B, 0x78, 0x71, 0x97, 0x1E, 0x92, 0x63, 0xB7, 0x1B, 0x19, 0x29, 0x8F, 0x39, 0xA3, 0xDD, 0xE4, 0x24, 0x5A, 0x26, 0x2F, 0x2E, 0xDB, 0xF7, 0xB5, 0xC7, 0x4B, 0x6B, 0x0C, 0x71, 0x2A, 0x43, 0x3D, 0x9D, 0xA7, 0x9E, 0xE6, 0xDE, 0x74, 0x9E, 0x7A, 0xB0, 0x55, 0x75, 0x5E,
0x49, 0xC9, 0xEA, 0xE4, 0xBD, 0xE3, 0xCE, 0xA3, 0xC3, 0x21, 0x2F, 0x9B, 0xEE, 0x42, 0x3D, 0xD5, 0x37, 0x93, 0xE6, 0x82, 0xDC, 0x4D, 0x51, 0x86, 0x1B, 0xDF, 0x96, 0x55, 0x74, 0x7E, 0x83, 0xCA, 0x1E, 0x21, 0xFE, 0x27, 0x53, 0xF8, 0xA8, 0x59, 0x0D, 0x94, 0x5E, 0xDB, 0xAC, 0xCD, 0x6A, 0x48, 0x2C, 0x09, 0x90, 0xCD,
0x16, 0x50, 0x07, 0xD7, 0x2E, 0xCC, 0x2E, 0x5E, 0xFF, 0xBD, 0x5E, 0x2D, 0x96, 0xEE, 0x69, 0x77, 0xF5, 0xD8, 0x66, 0xD6, 0x2A, 0x0B, 0x8C, 0xD3, 0x0E, 0x11, 0xFB, 0xD3, 0x90, 0x02, 0xB9, 0x5D, 0x49, 0x48, 0xA5, 0xCD, 0x19, 0x6E, 0xA6, 0x4F, 0xE2, 0x9E, 0x94, 0xCA, 0x4E, 0x59, 0x3B, 0xED, 0x3C, 0x3A, 0xC2, 0x7E,
0x07, 0xB7, 0x55, 0x0F, 0x3E, 0x44, 0x9C, 0x2B, 0x06, 0xCD, 0x52, 0x50, 0x88, 0x9A, 0xE5, 0x8D, 0x89, 0x69, 0x20, 0xE4, 0x93, 0x18, 0x70, 0x2C, 0xE2, 0x9A, 0x19, 0xEE, 0x36, 0xDD, 0x07, 0x7B, 0xEA, 0x6F, 0x26, 0x7D, 0x60, 0xA7, 0x8C, 0x36, 0xBE, 0x2D, 0xE0, 0x07, 0x37, 0x76, 0xCC, 0xB0, 0xBF, 0xB8, 0x99, 0x2F,
0xE6, 0x4D, 0x26, 0xF4, 0x5B, 0x3D, 0x8F, 0x30, 0x60, 0x04, 0x9F, 0xF1, 0x7A, 0xAF, 0x1F, 0x91, 0xA4, 0x1A, 0x11, 0xC7, 0x14, 0x46, 0xB4, 0x51, 0x13, 0xE3, 0x96, 0xAD, 0x69, 0x73, 0xFE, 0xD8, 0x6A, 0xD2, 0xAA, 0x12, 0x4C, 0xE2, 0x0E, 0x8B, 0x43, 0xDB, 0xAA, 0x07, 0x1F, 0xE2, 0x96, 0x6B, 0x06, 0xCD, 0x8A, 0x51,
0x86, 0x76, 0x67, 0x22, 0x38, 0x64, 0x22, 0x78, 0xFE, 0xEA, 0xBD, 0x4A, 0x06, 0xCC, 0xD7, 0x7A, 0x59, 0x11, 0x1C, 0x6E, 0xBE, 0x31, 0xBC, 0x5F, 0x59, 0x5A, 0x88, 0x8B, 0x15, 0x8D, 0x89, 0xB9, 0x21, 0x94, 0x41, 0x0C, 0x5C, 0x47, 0x76, 0xCD, 0xF0, 0x26, 0x13, 0xFE, 0xAC, 0x9E, 0x27, 0x64, 0x30, 0x82, 0x4F, 0x94,
0xBD, 0x58, 0x5A, 0x87, 0x93, 0x78, 0xCF, 0xD8, 0x36, 0x21, 0x4B, 0x21, 0x81, 0x23, 0xF6, 0x54, 0xA8, 0xF6, 0x56, 0xF6, 0x80, 0x4A, 0x76, 0x70, 0x54, 0xC7, 0x7E, 0x80, 0xCA, 0x4B, 0x46, 0xC4, 0x09, 0x86, 0x31, 0x6E, 0x5C, 0xC4, 0xA4, 0xA0, 0xDD, 0x1B, 0x09, 0xB0, 0xA0, 0x90, 0x48, 0xF0, 0xFA, 0x9B, 0x9F, 0x75,
0x0E, 0xAC, 0xC3, 0x2D, 0xCC, 0xE0, 0x28, 0xC7, 0x0C, 0xEE, 0x4A, 0x06, 0x43, 0x7D, 0xF4, 0x76, 0x13, 0x33, 0x18, 0x56, 0x34, 0x83, 0x43, 0x61, 0x06, 0xF1, 0x34, 0x10, 0xBA, 0x76, 0x90, 0x27, 0x01, 0x36, 0x86, 0xAD, 0xBA, 0x31, 0x1C, 0x19, 0x6A, 0x52, 0x8B, 0x8F, 0x5A, 0x05, 0xB5, 0x8E, 0x26, 0xC9, 0x9E, 0xB1,
0x86, 0xC2, 0x61, 0x55, 0x61, 0x49, 0x56, 0xF0, 0x68, 0x82, 0xEB, 0xE8, 0x8F, 0xAA, 0x79, 0xC2, 0xEE, 0x62, 0xEE, 0xCA, 0x76, 0xEB, 0xC7, 0xDB, 0xDF, 0x6C, 0x75, 0x4C, 0x96, 0x86, 0x02, 0x58, 0x1C, 0x4F, 0xAB, 0x42, 0x8D, 0xEF, 0x55, 0x0D, 0xA8, 0x25, 0x07, 0x18, 0x4B, 0xD7, 0x97, 0x03, 0x0B, 0x24, 0x5B, 0x59,
0xD7, 0xF2, 0x56, 0xF5, 0x42, 0xAE, 0xDC, 0xD1, 0xD7, 0x1E, 0x6E, 0xEB, 0x8D, 0x5A, 0x71, 0xAA, 0xA5, 0x73, 0x83, 0x95, 0xBD, 0x1B, 0x78, 0xBE, 0x96, 0x7D, 0x0C, 0x80, 0xA3, 0x56, 0x0C, 0xEE, 0x8B, 0x06, 0x58, 0x14, 0x4A, 0xCD, 0x6F, 0x2C, 0x06, 0xE8, 0x00, 0x6B, 0x89, 0x01, 0xDA, 0x2E, 0xC4, 0x20, 0xD9, 0x50,
0xED, 0x41, 0x62, 0x47, 0x92, 0x80, 0xAE, 0x56, 0x04, 0x64, 0x9F, 0xC1, 0x7E, 0xF5, 0xA3, 0xB6, 0xC1, 0x8E, 0x74, 0x05, 0x32, 0xBE, 0x71, 0x5F, 0xDB, 0x60, 0x98, 0xAC, 0x18, 0xAA, 0x20, 0x96, 0x22, 0x05, 0x4F, 0x20, 0x05, 0x87, 0x83, 0x27, 0xF5, 0x34, 0x61, 0x73, 0x36, 0xF7, 0x9A, 0xD6, 0x78, 0x34, 0xB5, 0xB7,
0xE7, 0xBE, 0x02, 0x5B, 0xCE, 0x33, 0xEB, 0xF8, 0x16, 0x05, 0x6D, 0xB3, 0xD7, 0x28, 0x94, 0x3E, 0xBE, 0xCD, 0xA0, 0x36, 0x4F, 0x29, 0xD1, 0xB8, 0x8C, 0x79, 0xBF, 0xD8, 0xAE, 0xE5, 0x5D, 0x37, 0x33, 0xB9, 0x6A, 0x45, 0x9F, 0xBB, 0xB9, 0x6D, 0x36, 0x6A, 0xA5, 0x50, 0x4B, 0x0F, 0x81, 0xA4, 0x4B, 0x84, 0xAD, 0x10,
0x2B, 0xD4, 0x58, 0xD5, 0xF6, 0xDC, 0x52, 0x9C, 0x92, 0x01, 0xF0, 0xE6, 0x37, 0xF4, 0xF1, 0xF6, 0x80, 0x54, 0xDB, 0xA5, 0x96, 0x26, 0xAC, 0x46, 0x65, 0xF8, 0xE4, 0xCC, 0x1F, 0x7B, 0x90, 0xDA, 0x91, 0x14, 0xE5, 0xAE, 0xE7, 0x04, 0xE4, 0xD7, 0x60, 0x7F, 0xF3, 0xB5, 0xB1, 0xC2, 0x8E, 0xF4, 0x82, 0x15, 0xE1, 0xD8,
0xE1, 0x54, 0x0A, 0x66, 0x51, 0xE7, 0x35, 0x83, 0x59, 0x5C, 0xE7, 0x83, 0x31, 0xED, 0x7D, 0xF0, 0xF2, 0x4F, 0x05, 0x4B, 0xEB, 0xCD, 0x59, 0x3A, 0xBC, 0x2B, 0xCB, 0x6C, 0xAC, 0xB0, 0x73, 0xBF, 0xFE, 0x9A, 0x75, 0x3A, 0x45, 0xC1, 0x58, 0xED, 0x18, 0x85, 0xCA, 0xE5, 0xDB, 0x8A, 0xEF, 0xB2, 0x5E, 0xBC, 0x42, 0x68,
0x96, 0xB6, 0x48, 0x55, 0x91, 0x75, 0x85, 0x5E, 0x68, 0x38, 0x1B, 0x1B, 0x17, 0x6B, 0x0D, 0xB6, 0xC5, 0x62, 0xAE, 0x76, 0x05, 0xAC, 0xEE, 0xD4, 0xC0, 0x04, 0x2B, 0x7C, 0xAC, 0x7A, 0x7B, 0x6E, 0xB3, 0x02, 0x20, 0x8B, 0x83, 0xA7, 0x58, 0xDE, 0x8E, 0xAB, 0x87, 0xF6, 0x0C, 0x3F, 0x9C, 0x2A, 0xC6, 0x2C, 0xAE, 0xBC,
0x01, 0xD5, 0x94, 0x31, 0xCC, 0x2A, 0xE3, 0xE4, 0x6B, 0xB3, 0x2F, 0xC6, 0x51, 0x55, 0xF3, 0x52, 0x70, 0x74, 0xFC, 0x35, 0x99, 0x97, 0xB7, 0x0C, 0xF1, 0xEA, 0xA1, 0x31, 0x4B, 0xFC, 0x7C, 0x08, 0xD3, 0xD6, 0x07, 0x2F, 0x7F, 0xD7, 0x34, 0x09, 0xF1, 0xDF, 0x55, 0x9B, 0x74, 0x74, 0x5F, 0x4D, 0x5A, 0xA3, 0xAB, 0x8A,
0xC6, 0xC1, 0x8B, 0x35, 0xC7, 0xE0, 0x45, 0x8F, 0x76, 0x6F, 0x60, 0x11, 0x05, 0x1B, 0xEB, 0xE3, 0xF0, 0x4E, 0xDF, 0xD7, 0x74, 0x17, 0x11, 0x8C, 0xB1, 0xB4, 0xA5, 0x2B, 0xF4, 0x42, 0x3C, 0x9F, 0x70, 0x55, 0xE1, 0x12, 0xA5, 0x21, 0x5B, 0xC2, 0xE6, 0x1A, 0x97, 0x68, 0xEA, 0x46, 0x05, 0x2C, 0x42, 0xA0, 0x1E, 0x33,
0x85, 0x89, 0x0D, 0x86, 0x3B, 0x34, 0x31, 0x69, 0x19, 0x89, 0xE7, 0x41, 0x5E, 0xC0, 0xE8, 0x7C, 0x6D, 0x20, 0x2E, 0x68, 0xEA, 0xAC, 0x24, 0xA9, 0xB3, 0xF2, 0xE2, 0x48, 0x4B, 0xC2, 0x0C, 0x98, 0x97, 0xCF, 0x4B, 0xBE, 0x44, 0x8B, 0xEA, 0x8A, 0x97, 0xA6, 0x45, 0xB0, 0x66, 0x9F, 0x8F, 0x78, 0xE1, 0x78, 0x32, 0x4A,
0xD9, 0x01, 0x14, 0x85, 0x59, 0x04, 0x39, 0x74, 0x9E, 0xB1, 0xCF, 0xBE, 0xA9, 0x3B, 0x8C, 0x5F, 0xD3, 0x46, 0xD7, 0xB9, 0xE2, 0x17, 0x82, 0x46, 0x85, 0x66, 0x5D, 0xD9, 0x78, 0x89, 0xE2, 0x64, 0xBC, 0xF8, 0xD5, 0xE6, 0x05, 0x2C, 0xC6, 0x60, 0x65, 0x7E, 0xE0, 0xC0, 0x93, 0xCF, 0xCC, 0x82, 0x89, 0x26, 0xAD, 0x21,
0xFA, 0x45, 0xA1, 0xA5, 0xAF, 0x44, 0x3B, 0x33, 0xF8, 0x9E, 0xFC, 0x6B, 0xC2, 0x17, 0xE5, 0xB4, 0x99, 0x4F, 0x26, 0xE7, 0xFA, 0x77, 0x11, 0x4E, 0x2E, 0x2D, 0x62, 0x38, 0x36, 0x65, 0x73, 0x22, 0xA6, 0x4C, 0x23, 0xC9, 0x7E, 0x50, 0x3A, 0x30, 0x3C, 0x5A, 0x99, 0x72, 0x68, 0x9A, 0xCC, 0x24, 0xE9, 0x7B, 0xE5, 0xB3,
0x04, 0xD1, 0x35, 0x08, 0xC9, 0xAE, 0xE3, 0x19, 0x58, 0xAC, 0x1A, 0x8B, 0x10, 0x28, 0xED, 0xFE, 0xB1, 0xC0, 0x49, 0x5E, 0x03, 0x37, 0x70, 0x1B, 0xD5, 0xD6, 0x7D, 0x38, 0x85, 0x9A, 0x23, 0xD7, 0xF4, 0x78, 0x9E, 0x89, 0xC7, 0xBE, 0x15, 0x1C, 0x97, 0x16, 0x1F, 0xD3, 0xC6, 0xE7, 0xB9, 0x92, 0x03, 0x41, 0x63, 0x47,
0x71, 0xE9, 0xAB, 0x45, 0xF9, 0x4A, 0x3B, 0x1E, 0x46, 0x8B, 0x78, 0xFF, 0xF3, 0xDF, 0x65, 0x53, 0x33, 0xF8, 0xF1, 0xBF, 0x58, 0x00, 0x60, 0x46, 0xBE, 0x79, 0x33, 0x7B, 0x50, 0x68, 0xE5, 0x91, 0x68, 0x67, 0xA6, 0xDC, 0x93, 0x7F, 0x45, 0x73, 0x69, 0x34, 0x29, 0x67, 0xCC, 0x7C, 0x36, 0x39, 0x6F, 0x7D, 0x19, 0xC3,
0xAE, 0x03, 0xA5, 0xBE, 0x17, 0x40, 0x29, 0x6A, 0x4F, 0xED, 0x1C, 0x55, 0xE5, 0x49, 0xFB, 0x40, 0x25, 0xEE, 0x14, 0xB0, 0x62, 0x6C, 0x72, 0x16, 0x98, 0xBE, 0x94, 0xD4, 0xA2, 0x2C, 0x2D, 0x03, 0x26, 0xD9, 0x75, 0x3C, 0x93, 0x9C, 0x55, 0x73, 0x81, 0x7D, 0xFC, 0xAC, 0xFF, 0xDB, 0x82, 0x82, 0xBC, 0xB8, 0x79, 0xB6,
0xBD, 0x80, 0x52, 0xCD, 0xF2, 0xCC, 0xE5, 0x9C, 0xB8, 0x61, 0xD7, 0xB0, 0xAC, 0xCB, 0x6B, 0x38, 0x78, 0x8D, 0x33, 0xCC, 0x20, 0xF9, 0x66, 0xE3, 0xF9, 0xCF, 0x6F, 0xD6, 0x9B, 0xC7, 0xE5, 0x47, 0x8B, 0xCA, 0x99, 0x76, 0xBA, 0x8C, 0x27, 0xF1, 0xFE, 0xEF, 0xFF, 0x55, 0x85, 0x66, 0xE8, 0xE1, 0x7F, 0x09, 0x01, 0x20,
0x6F, 0x2E, 0xD8, 0x0B, 0xF7, 0x5E, 0x83, 0xBC, 0x88, 0xD5, 0x68, 0x6B, 0x93, 0xA5, 0xCB, 0xAA, 0xF7, 0x26, 0x41, 0x58, 0xF6, 0x11, 0xC6, 0x6B, 0xC3, 0xD7, 0x46, 0xFE, 0xF8, 0xBC, 0x05, 0x4C, 0x7D, 0x2F, 0x80, 0x2B, 0x6A, 0x63, 0x92, 0xAE, 0x80, 0x72, 0x05, 0xD4, 0xDE, 0xD7, 0x91, 0x3B, 0x93, 0x59, 0x33, 0x36,
0xC6, 0x46, 0x40, 0x5E, 0x7A, 0x41, 0xA8, 0x9D, 0x6B, 0x11, 0x46, 0xC7, 0x33, 0xE9, 0x4B, 0x12, 0xBA, 0x8C, 0x2F, 0x0E, 0xC9, 0x18, 0xFF, 0xD5, 0x77, 0x00, 0x39, 0x0B, 0xC6, 0xBE, 0xBD, 0x80, 0xAB, 0x86, 0xC7, 0x00, 0x2F, 0x71, 0x76, 0x5D, 0xD8, 0x47, 0x44, 0xF5, 0xE2, 0x0A, 0x17, 0xEF, 0x28, 0xC2, 0x0C, 0xCA,
0x34, 0x6A, 0xF5, 0x50, 0x6B, 0x9C, 0x9E, 0xF4, 0x1B, 0x68, 0x7F, 0x51, 0x17, 0x13, 0xFC, 0xAC, 0x22, 0xC0, 0x35, 0x97, 0xBE, 0xD3, 0xD6, 0xCC, 0x71, 0x8B, 0x77, 0xDA, 0xAF, 0xBF, 0x7B, 0x4F, 0x07, 0x60, 0x50, 0x1A, 0xE8, 0xC5, 0xAC, 0x76, 0xD7, 0x98, 0x2C, 0x5D, 0xE1, 0xBD, 0x77, 0xB0, 0x6D, 0xC6, 0x0D, 0xC5,
0xBD, 0x24, 0x91, 0x5E, 0xC6, 0x6B, 0xE2, 0xED, 0xB9, 0xDD, 0x70, 0x46, 0xDC, 0x66, 0x4C, 0x19, 0x38, 0xC3, 0xC2, 0x73, 0x83, 0xC4, 0x17, 0x22, 0xED, 0x49, 0x43, 0x18, 0xAF, 0x4C, 0x1F, 0x47, 0x9F, 0x06, 0xEC, 0xAD, 0x17, 0x84, 0xC6, 0x39, 0x08, 0x2C, 0x21, 0xE2, 0x50, 0x47, 0x7E, 0x48, 0x42, 0x5F, 0xB4, 0x4B,
0x7C, 0xBD, 0x0B, 0x05, 0x7D, 0xB8, 0x0C, 0xB4, 0xFB, 0xE7, 0xE7, 0x1A, 0x16, 0xB8, 0x89, 0x97, 0x2F, 0x9A, 0xE3, 0x34, 0x5C, 0x5B, 0x4B, 0x5D, 0xF8, 0x05, 0xE6, 0x14, 0x0D, 0xFF, 0xC9, 0x77, 0x90, 0x35, 0x2E, 0xB5, 0x67, 0xB4, 0x4F, 0x9F, 0x1E, 0xB6, 0x49, 0xFE, 0xE2, 0x2A, 0x26, 0xF4, 0x58, 0x45, 0xE4, 0xEB,
0x42, 0x83, 0xF4, 0x9A, 0xDF, 0x5B, 0x8D, 0x38, 0xA9, 0xF7, 0xCC, 0x46, 0x0D, 0x30, 0x8A, 0x34, 0x5B, 0x49, 0x02, 0x9B, 0x96, 0x11, 0x1A, 0xAD, 0xE4, 0x0B, 0x2C, 0x7D, 0xA7, 0x6B, 0x8C, 0x47, 0xBB, 0xE2, 0x90, 0x44, 0x9E, 0x4C, 0x69, 0xD1, 0xE9, 0xB9, 0xFD, 0x70, 0xC6, 0xDC, 0x4E, 0x82, 0x19, 0x94, 0x61, 0x81,
0x1F, 0xA1, 0x57, 0xA0, 0xA4, 0xAD, 0xD1, 0x5B, 0xF2, 0xDB, 0x27, 0x6F, 0x5B, 0x5D, 0x90, 0x21, 0xF0, 0x1B, 0xB5, 0x26, 0xBE, 0x9F, 0xFE, 0xF4, 0x25, 0xB4, 0xF9, 0xDC, 0xD4, 0x13, 0x22, 0xED, 0x49, 0x92, 0xDE, 0x87, 0x43, 0x1F, 0xE2, 0xF9, 0x2E, 0x8F, 0xCE, 0xCF, 0x71, 0x6E, 0xE6, 0x41, 0xFA, 0x41, 0x92, 0xE3,
0xEE, 0xF4, 0xDB, 0x1A, 0xDE, 0x49, 0xB6, 0x95, 0x88, 0xBC, 0x27, 0xAE, 0x09, 0xA1, 0x15, 0xA3, 0x55, 0xA0, 0x64, 0xE8, 0x6E, 0x13, 0x2A, 0x82, 0xD8, 0xF3, 0x51, 0x36, 0x5F, 0x17, 0xA3, 0xC4, 0x54, 0xC2, 0x8F, 0x30, 0x0D, 0xCA, 0x31, 0xBF, 0x77, 0x06, 0x73, 0x32, 0xE7, 0xCC, 0xC6, 0x05, 0xC8, 0x8A, 0x74, 0x76,
0x8E, 0x4C, 0x41, 0x62, 0xD3, 0x36, 0x1F, 0x40, 0xB7, 0xE9, 0xE8, 0xB9, 0xCD, 0x82, 0xA2, 0xA4, 0xB5, 0x83, 0x03, 0x70, 0x69, 0x08, 0x4A, 0x04, 0xAC, 0x62, 0xD3, 0x08, 0x76, 0x2C, 0x33, 0x34, 0x65, 0x5B, 0x94, 0x5A, 0x81, 0x49, 0xD7, 0xE0, 0xB7, 0xD4, 0xD3, 0x27, 0xEF, 0x76, 0xFB, 0xA0, 0x21, 0xDA, 0x1B, 0x97,
0xDA, 0x6C, 0xF0, 0x05, 0x4C, 0xB0, 0xA8, 0x46, 0xEF, 0xA6, 0xF1, 0x10, 0x10, 0x74, 0x43, 0xEF, 0x2A, 0xF4, 0x6D, 0x77, 0x0A, 0x43, 0x8F, 0x56, 0x8C, 0x8D, 0x66, 0xBE, 0x9F, 0x7D, 0xF4, 0x25, 0x4A, 0xF7, 0x0E, 0xBB, 0x06, 0xDD, 0x49, 0x97, 0x55, 0x90, 0x94, 0x57, 0x77, 0x31, 0xD1, 0xCA, 0xC1, 0x6A, 0x40, 0x0A,
0xDE, 0x46, 0x94, 0xA9, 0xFB, 0xF4, 0x3A, 0xED, 0x24, 0x7D, 0xA3, 0xC9, 0xAF, 0x3F, 0x6C, 0xB4, 0x1A, 0x9C, 0x78, 0x7A, 0x0E, 0xE6, 0xD6, 0x64, 0x07, 0x0F, 0x70, 0xFC, 0xF0, 0xC9, 0x98, 0xD6, 0xB0, 0x3D, 0x98, 0x04, 0x00, 0xC5, 0x30, 0x11, 0x20, 0x7C, 0xC0, 0x2E, 0x1F, 0x3D, 0x77, 0x85, 0x51, 0x54, 0xB8, 0xB6,
0x28, 0x8D, 0x2D, 0xED, 0xEC, 0x8C, 0x77, 0xC3, 0xA0, 0xF0, 0x22, 0x00, 0xD1, 0x3F, 0xA9, 0x5B, 0x91, 0x29, 0x7E, 0xFA, 0xFE, 0x2F, 0x61, 0xB3, 0xB7, 0x07, 0xBF, 0x0F, 0x95, 0x86, 0x51, 0x62, 0x90, 0x8A, 0x69, 0xA7, 0x2D, 0x27, 0x30, 0x21, 0x51, 0xED, 0x83, 0x9B, 0xF6, 0x1E, 0x00, 0xE0, 0x44, 0x4C, 0xCC, 0x7D,
0x40, 0xF5, 0x13, 0x9C, 0x41, 0xF8, 0xFE, 0x2F, 0xF8, 0xFF, 0xED, 0x03, 0x3A, 0x6D, 0xF0, 0xFD, 0x5F, 0xF8, 0xE7, 0xF6, 0x01, 0xF4, 0x04, 0xC7, 0xB4, 0xBF, 0x63, 0x7A, 0x19, 0x43, 0x8F, 0xDD, 0x04, 0x1A, 0xBF, 0x4D, 0x20, 0x33, 0xF7, 0x79, 0x3A, 0xAF, 0x24, 0x7B, 0xA3, 0x23, 0xD3, 0xF7, 0xDA, 0xBB, 0x6D, 0x89,
0xDB, 0x4F, 0x54, 0x0E, 0x59, 0xE9, 0x4D, 0x73, 0xA5, 0x17, 0x89, 0xAD, 0x36, 0x4D, 0xD3, 0x02, 0xA2, 0x3E, 0xC5, 0xFE, 0xDB, 0x34, 0x3D, 0x0B, 0xD4, 0x13, 0x3C, 0xFF, 0x0F, 0x71, 0xEB, 0x88, 0x8B, 0x1D, 0x8E, 0xE3, 0xAE, 0x71, 0x76, 0x26, 0xAB, 0x11, 0xB9, 0x28, 0x11, 0x99, 0xF8, 0x4F, 0xE6, 0x56, 0x2C, 0x8A,
0x82, 0x25, 0x0B, 0xA5, 0x3B, 0xA0, 0x12, 0x21, 0xA8, 0xE8, 0x0D, 0xA8, 0xF6, 0x84, 0x42, 0x6A, 0xDC, 0x55, 0x62, 0x03, 0x11, 0x90, 0x0B, 0xFC, 0x2C, 0xF8, 0xBF, 0x7E, 0xF5, 0x47, 0x24, 0xB3, 0x77, 0xFB, 0xC0, 0xFA, 0x39, 0x45, 0x10, 0xBE, 0xFA, 0x03, 0xDF, 0x77, 0x3B, 0x3C, 0x6C, 0xF0, 0xD5, 0x1F, 0xF4, 0x73,
0x2B, 0x37, 0x6C, 0x86, 0x09, 0xA7, 0xC8, 0x91, 0xF8, 0x68, 0x94, 0x60, 0x01, 0x7F, 0xD0, 0x0E, 0xE0, 0x1A, 0x5C, 0x69, 0x91, 0xB1, 0xDD, 0x8B, 0xEC, 0x30, 0xB7, 0x83, 0x9A, 0x70, 0xCD, 0xEB, 0xBB, 0xFB, 0x95, 0xD3, 0x21, 0x4F, 0x3D, 0x44, 0x89, 0x0B, 0xA8, 0x17, 0x93, 0xAD, 0x31, 0x4E, 0x38, 0xF0, 0xBC, 0x10,
0xA6, 0x94, 0xDD, 0xCC, 0xB1, 0xC3, 0x0F, 0xA6, 0xF3, 0xB9, 0x89, 0xEF, 0x64, 0x4C, 0x87, 0x8A, 0x8C, 0x88, 0x10, 0xE8, 0x09, 0xFE, 0x0F, 0xE4, 0x82, 0x7F, 0x29, 0xE0, 0x11, 0xF3, 0x7B, 0x8C, 0xDD, 0xCF, 0x5D, 0x23, 0x84, 0x24, 0x47, 0x4C, 0x77, 0xC0, 0x92, 0x88, 0x50, 0xF1, 0x09, 0xA8, 0xF6, 0x84, 0xE7, 0x34,
0x72, 0xF5, 0x03, 0x58, 0x59, 0x09, 0xDF, 0xA4, 0x53, 0x00, 0x1F, 0x6F, 0xDA, 0x1A, 0x3B, 0x58, 0x83, 0x67, 0xB8, 0x16, 0x9E, 0xE3, 0x9F, 0xB5, 0xD0, 0x1E, 0xA4, 0xAA, 0x24, 0x02, 0x12, 0xE5, 0xC4, 0xC3, 0x2E, 0x02, 0x86, 0x05, 0x28, 0x1D, 0x02, 0x95, 0xC8, 0x5B, 0x01, 0xC5, 0x87, 0xC3, 0x54, 0x13, 0xF8, 0x81,
0x5E, 0xE0, 0x47, 0x70, 0x8D, 0xD6, 0xAC, 0x78, 0x89, 0x1D, 0x20, 0x14, 0xAD, 0x31, 0x28, 0x14, 0x3B, 0x82, 0x6B, 0xF8, 0xCE, 0x0F, 0xB0, 0xDD, 0xB6, 0x36, 0xC4, 0x37, 0x64, 0x33, 0xDA, 0x92, 0x69, 0xB1, 0xB0, 0xC9, 0x5F, 0xC8, 0x61, 0x82, 0xA9, 0xB8, 0x59, 0x20, 0x87, 0x1F, 0x70, 0x1C, 0x63, 0x87, 0xCE, 0x64,
0xB6, 0x5D, 0x97, 0x1E, 0x94, 0x50, 0x1F, 0xA7, 0xFA, 0x27, 0xC1, 0x0D, 0x70, 0xC0, 0x49, 0xBB, 0x7D, 0x10, 0xAC, 0xA3, 0xB3, 0xF5, 0xED, 0x03, 0x82, 0xF7, 0xCC, 0x9A, 0x8A, 0x1C, 0x89, 0x28, 0xD3, 0x73, 0xFA, 0x02, 0x5D, 0xE8, 0xA7, 0x90, 0x3F, 0x80, 0x2A, 0x5C, 0xF8, 0x0E, 0x0F, 0x01, 0x7C, 0xBC, 0xE9, 0xC2,
0x28, 0x91, 0x70, 0xBC, 0xE6, 0xC7, 0x70, 0x1D, 0xE8, 0xC3, 0x3B, 0x82, 0x60, 0x7A, 0x61, 0x1D, 0x5F, 0x00, 0x88, 0x10, 0xEF, 0x73, 0xE2, 0xE1, 0x6C, 0x1D, 0x78, 0xD1, 0xC5, 0x2D, 0x34, 0xC3, 0xB5, 0xE8, 0x3F, 0xFD, 0xE0, 0x9F, 0x68, 0x14, 0x25, 0xC8, 0x2B, 0xA4, 0x71, 0x9F, 0x95, 0x92, 0xC4, 0x05, 0xE5, 0xE2,
0x9D, 0x61, 0x6B, 0xDA, 0x96, 0xB3, 0x01, 0xA7, 0xEB, 0xF8, 0x14, 0xEE, 0xB2, 0x0F, 0xBA, 0x03, 0x11, 0x8C, 0xA7, 0xDB, 0x07, 0x9C, 0x27, 0xB8, 0xC4, 0x8F, 0x3E, 0x06, 0xCF, 0x25, 0xAE, 0x90, 0x46, 0x67, 0x7E, 0x40, 0x76, 0xBB, 0xC6, 0xC8, 0x76, 0x5D, 0x7E, 0x51, 0x81, 0x7D, 0xD2, 0xD5, 0x3F, 0x0F, 0x6E, 0xD0,
0xD2, 0xA2, 0xC6, 0x98, 0x10, 0xF2, 0x28, 0xF2, 0x8C, 0x25, 0x69, 0x29, 0x7F, 0x80, 0x7F, 0x5C, 0x3A, 0x04, 0x0F, 0x9F, 0xAD, 0x5F, 0x59, 0xCD, 0x06, 0x5F, 0x02, 0x89, 0xDA, 0xDD, 0x4E, 0x70, 0x1B, 0xFF, 0xBB, 0xBD, 0xDB, 0x61, 0x74, 0x8F, 0x23, 0x89, 0x6B, 0xBA, 0xC3, 0x31, 0xBD, 0xDB, 0x01, 0x7E, 0x74, 0x27,
0x90, 0x6D, 0x60, 0x0C, 0x93, 0xDB, 0x74, 0x3D, 0xD7, 0x74, 0x6C, 0x13, 0x1D, 0xA5, 0xD9, 0xD2, 0xCE, 0x47, 0x3C, 0x8E, 0xA1, 0x41, 0x03, 0xB8, 0x6C, 0xA4, 0x42, 0x98, 0x27, 0xD0, 0xED, 0x08, 0xEF, 0xBB, 0x9D, 0x90, 0xEE, 0x4B, 0xE4, 0xF1, 0x8F, 0x6E, 0xCA, 0x16, 0x20, 0x33, 0x2F, 0x2B, 0x9B, 0x81, 0xBF, 0xBC,
0xB9, 0xA8, 0xC5, 0x92, 0x62, 0xA3, 0xD5, 0xA5, 0x76, 0xC8, 0x6D, 0x0D, 0x51, 0x70, 0x17, 0xAC, 0x86, 0x03, 0x81, 0x15, 0x38, 0x32, 0xDE, 0x52, 0x88, 0x84, 0xA4, 0x6C, 0x0B, 0x30, 0xE0, 0x0F, 0x74, 0x07, 0x12, 0xA2, 0x4D, 0x77, 0x3B, 0xB2, 0x4D, 0x48, 0x92, 0x57, 0x59, 0x52, 0x93, 0x4D, 0x08, 0xA5, 0x15, 0x79,
0x42, 0x4B, 0x58, 0x28, 0x1A, 0x39, 0xD4, 0xF6, 0x52, 0x51, 0xB6, 0xC0, 0xAB, 0x85, 0x03, 0xDF, 0x4F, 0x3B, 0x30, 0xA8, 0xCA, 0x0F, 0x9B, 0x8D, 0x4B, 0x7C, 0x29, 0x3A, 0x69, 0xA5, 0xFF, 0x80, 0x7E, 0x5C, 0x38, 0x8C, 0x2E, 0x5F, 0xDE, 0x7E, 0x63, 0x75, 0xDA, 0x72, 0x42, 0xB6, 0x4D, 0x36, 0x4C, 0x2D, 0xD3, 0xF7,
0x10, 0xF8, 0xF7, 0xC6, 0x43, 0x04, 0x7A, 0xD8, 0xF8, 0xD7, 0xA9, 0xD6, 0x78, 0x28, 0x7B, 0xF2, 0x6D, 0xDA, 0xE5, 0x98, 0xC6, 0xA6, 0x15, 0x35, 0x36, 0x95, 0xDC, 0xB1, 0x63, 0xE3, 0xF1, 0x31, 0x90, 0xB7, 0x5D, 0xE3, 0x7C, 0x28, 0xED, 0x18, 0x09, 0x34, 0xB2, 0xAB, 0x42, 0x5A, 0x08, 0x3A, 0x9A, 0x52, 0x6C, 0xEF,
0x34, 0x36, 0xBD, 0x5B, 0x8D, 0xC9, 0x0B, 0xC1, 0xDB, 0x68, 0x4D, 0x5E, 0x79, 0x2D, 0xD0, 0x5C, 0x69, 0x7B, 0xAE, 0x34, 0xAE, 0xAD, 0xA9, 0x4A, 0x5B, 0x9B, 0xF6, 0xB9, 0x1C, 0x4A, 0x59, 0x23, 0x10, 0x52, 0x05, 0xEB, 0xC1, 0xA0, 0xCC, 0x1A, 0x18, 0x39, 0x6D, 0x29, 0x05, 0xC2, 0x73, 0x2B, 0x50, 0x38, 0x18, 0xD5,
0xA8, 0x89, 0xA5, 0x38, 0xF0, 0x1E, 0xE2, 0xBF, 0xFC, 0xE5, 0xCD, 0x6B, 0x0C, 0x95, 0x6A, 0x95, 0x45, 0x1A, 0x4B, 0x97, 0x23, 0x0A, 0x0C, 0x98, 0x3B, 0x13, 0xD4, 0xA2, 0xA7, 0x48, 0x59, 0xD9, 0x12, 0xAD, 0x8E, 0x14, 0xF8, 0x51, 0x56, 0x81, 0xC1, 0x2A, 0x3F, 0xEC, 0xB4, 0x2F, 0x68, 0x21, 0xF0, 0x3F, 0xDA, 0x7B,
0x81, 0x3B, 0x91, 0x43, 0x1F, 0x36, 0xB4, 0x26, 0x45, 0x89, 0x19, 0xB4, 0xC4, 0x10, 0x78, 0xE0, 0xAD, 0xE6, 0xBB, 0x18, 0x6C, 0x85, 0xF3, 0xC6, 0xAD, 0x0A, 0x94, 0x69, 0xAF, 0xFD, 0xCF, 0x53, 0xA3, 0xBD, 0xA7, 0x6A, 0xB2, 0xD0, 0x43, 0x45, 0xE5, 0x04, 0xC7, 0x84, 0xE5, 0xAA, 0xE6, 0x98, 0x9C, 0x07, 0xE3, 0x1C,
0x6C, 0x01, 0x1B, 0x54, 0x52, 0x22, 0xC3, 0x9C, 0x71, 0x18, 0x29, 0x27, 0xEC, 0xDC, 0x45, 0xA8, 0xBF, 0x06, 0x55, 0x83, 0x9A, 0x88, 0xE9, 0x71, 0x6C, 0x0B, 0x53, 0xCB, 0xDC, 0x03, 0xC7, 0xD4, 0x89, 0xE0, 0x75, 0xB8, 0xA6, 0xCE, 0xBC, 0x96, 0x70, 0xAE, 0xB2, 0xBC, 0x64, 0x9A, 0xE4, 0x96, 0x6A, 0xDA, 0x63, 0x6E,
0x4A, 0xA5, 0xC3, 0x23, 0x7F, 0x25, 0x01, 0xF1, 0x39, 0x6C, 0x85, 0x81, 0x8B, 0x4C, 0x50, 0x09, 0x8D, 0x98, 0xBA, 0xCC, 0xC7, 0xB3, 0xAE, 0x83, 0x67, 0xAD, 0xAD, 0xC2, 0x26, 0xD1, 0xC5, 0x41, 0x7B, 0x98, 0xFF, 0xF6, 0xC7, 0xF7, 0xEF, 0xC8, 0x54, 0xEA, 0x59, 0x16, 0x73, 0x2C, 0xEB, 0x8E, 0x68, 0x20, 0x50, 0xDF,
0xC0, 0xC3, 0x33, 0x4F, 0x25, 0x34, 0x7C, 0xA2, 0x2B, 0x17, 0x4B, 0x35, 0x62, 0xF8, 0xE4, 0x92, 0x8A, 0x27, 0x9E, 0xE9, 0xAA, 0xF1, 0xC4, 0x27, 0x45, 0xF2, 0x99, 0x32, 0xDC, 0xA9, 0x3E, 0x74, 0xAF, 0x6D, 0xA0, 0x0F, 0x45, 0x32, 0xF5, 0xA0, 0x15, 0x82, 0x20, 0x0D, 0x6F, 0x3D, 0xDD, 0x25, 0x63, 0x1B, 0x29, 0x6F,
0xF1, 0x54, 0x94, 0x0D, 0x9F, 0x89, 0x50, 0xD8, 0x73, 0xBA, 0x1A, 0xE9, 0x89, 0xFF, 0x36, 0xAF, 0x3F, 0x26, 0x06, 0x44, 0x8B, 0xF8, 0xCF, 0x5E, 0xBC, 0x64, 0x52, 0xAA, 0x44, 0x16, 0xA8, 0x40, 0x2D, 0x26, 0x0A, 0xC8, 0x39, 0x85, 0x51, 0xFA, 0x84, 0x8D, 0xAB, 0x08, 0xD7, 0xD7, 0xA0, 0xAE, 0x51, 0x8B, 0x6C, 0x7A,
0xFA, 0x5E, 0x54, 0x8B, 0xC4, 0x51, 0x66, 0x03, 0xE2, 0x74, 0x8D, 0x10, 0xE2, 0x13, 0x8C, 0xE3, 0x49, 0xD0, 0xC5, 0x0A, 0x37, 0x12, 0x63, 0xE6, 0x56, 0xD7, 0x62, 0xDB, 0x64, 0xD1, 0x12, 0xEA, 0x48, 0xCB, 0x5F, 0x8B, 0x40, 0x32, 0x86, 0xAD, 0x11, 0xF0, 0xA8, 0x27, 0xA8, 0x05, 0x26, 0x0A, 0x5D, 0x16, 0xC3, 0xB9,
0x05, 0x02, 0x28, 0xC2, 0xD6, 0x69, 0x2F, 0x6D, 0x9E, 0x19, 0x5C, 0xEC, 0x72, 0x1E, 0x3A, 0x76, 0x37, 0x07, 0x23, 0xCF, 0x30, 0xC9, 0x16, 0x78, 0x31, 0x0F, 0x6D, 0x02, 0xE7, 0x56, 0x03, 0x47, 0xF6, 0x3C, 0xB5, 0xC0, 0xC8, 0x40, 0x57, 0x21, 0x94, 0x7A, 0xC8, 0xC8, 0xE0, 0x92, 0xAE, 0x4D, 0xB2, 0xA7, 0xAB, 0xD7,
0x1B, 0x1D, 0xC5, 0x48, 0xB8, 0x06, 0x47, 0x47, 0xD9, 0x3C, 0xC3, 0x3B, 0xE0, 0x9F, 0x7E, 0x42, 0x0C, 0x38, 0x1F, 0x15, 0x0F, 0xCD, 0x4C, 0x28, 0x04, 0xB5, 0x26, 0x19, 0x14, 0x29, 0x86, 0x53, 0x93, 0x36, 0x32, 0x12, 0xA1, 0x91, 0xE7, 0xAC, 0x37, 0x02, 0xCB, 0x22, 0x3E, 0xAB, 0xFB, 0x1F, 0x13, 0x13, 0xD6, 0x22,
0x86, 0x58, 0xB2, 0x6B, 0x9C, 0x66, 0x2A, 0x6E, 0x68, 0xC1, 0x17, 0xE1, 0xB4, 0x27, 0x8C, 0xC6, 0xC4, 0x07, 0x0D, 0xC6, 0x30, 0xF8, 0x8E, 0xBE, 0x5B, 0xC4, 0xF9, 0xD9, 0x8A, 0x96, 0x4C, 0xF9, 0xEA, 0x0C, 0x92, 0x70, 0xE6, 0x68, 0x7B, 0x03, 0x3C, 0x72, 0xC0, 0x0C, 0x61, 0x9F, 0x30, 0x8E, 0x67, 0x41, 0x9F, 0x3C,
0x90, 0xD1, 0x07, 0xAB, 0x23, 0x4C, 0xEC, 0x1A, 0x0E, 0x5C, 0x53, 0x97, 0xD8, 0xDA, 0x4E, 0xC7, 0x73, 0x89, 0xBA, 0xD7, 0x44, 0xFD, 0xCE, 0x3B, 0xE2, 0x67, 0xDC, 0x98, 0x8C, 0xB9, 0x5B, 0x7D, 0x17, 0x08, 0x70, 0x80, 0xBB, 0xA7, 0xD2, 0x8D, 0x4D, 0xC4, 0x33, 0x07, 0x4B, 0x24, 0x17, 0x81, 0x13, 0x77, 0x0B, 0x20,
0xFC, 0x89, 0xEF, 0xB8, 0x99, 0x4F, 0xC2, 0xA5, 0xEF, 0xF2, 0x7A, 0x3E, 0x5B, 0xDF, 0x28, 0x87, 0x92, 0x3B, 0xB4, 0xCD, 0x83, 0x03, 0xED, 0x69, 0x18, 0x1A, 0xCA, 0x1E, 0x26, 0x5D, 0x82, 0x12, 0x8B, 0xA0, 0xF1, 0x51, 0x8C, 0x02, 0x0B, 0xAB, 0x98, 0xF3, 0xFD, 0x8C, 0xAC, 0x40, 0x3E, 0xFA, 0x89, 0x20, 0x50, 0x3C,
0xA0, 0x00, 0x5C, 0xA7, 0x9C, 0xA1, 0x7C, 0x34, 0x83, 0x4F, 0x4A, 0x78, 0x3E, 0x1A, 0x25, 0x7B, 0xA8, 0x98, 0x30, 0xBF, 0xC5, 0xCF, 0x3C, 0x09, 0x77, 0xA6, 0x2A, 0x19, 0x9A, 0x8D, 0xE1, 0x08, 0x1A, 0xED, 0x68, 0xCA, 0xAE, 0x7D, 0x9A, 0xF3, 0xB8, 0x51, 0x42, 0x4E, 0xC2, 0x19, 0xCF, 0x05, 0x8E, 0xA9, 0x07, 0x1A,
0xA8, 0xBA, 0xFF, 0x5E, 0x12, 0x7F, 0x7D, 0x45, 0x05, 0xE6, 0xF9, 0x4F, 0x1D, 0xA7, 0xD9, 0xE8, 0xC6, 0xCB, 0xCE, 0x0D, 0x36, 0x06, 0xEF, 0x02, 0xAA, 0x4B, 0x8C, 0x30, 0xF8, 0x8E, 0x9F, 0x5B, 0x24, 0x80, 0xF1, 0x85, 0xD5, 0x31, 0x24, 0x91, 0x46, 0x03, 0xD7, 0x4C, 0x92, 0x98, 0xDB, 0xE9, 0xE1, 0x69, 0x04, 0xFA,
0xE8, 0x03, 0x74, 0x1C, 0xDB, 0x3C, 0xE3, 0x26, 0xD2, 0x3B, 0x8C, 0xBB, 0xCE, 0xB9, 0x32, 0xD2, 0x83, 0x7E, 0x80, 0xF0, 0xDC, 0xCF, 0x64, 0xBD, 0x5C, 0x80, 0x5A, 0x53, 0xFE, 0xBB, 0xAC, 0x48, 0xFE, 0x93, 0x2B, 0xBE, 0x93, 0x62, 0x3E, 0x43, 0xE0, 0xC5, 0x95, 0xFE, 0x7C, 0xDE, 0xBF, 0xD1, 0x0E, 0x25, 0x37, 0x28,
0xF8, 0xE3, 0x61, 0x7C, 0x6A, 0x62, 0x81, 0x4B, 0x87, 0x74, 0x01, 0xF2, 0x82, 0x0F, 0xE4, 0xFA, 0x87, 0x0A, 0xA0, 0x58, 0x05, 0xD4, 0x3A, 0xD1, 0x13, 0xB3, 0x9B, 0xFB, 0xFB, 0xC6, 0x8B, 0x30, 0x34, 0xC1, 0x00, 0x9A, 0xA7, 0x9C, 0x11, 0x7D, 0x0C, 0x31, 0x65, 0x4C, 0x11, 0x58, 0x12, 0x4A, 0xB1, 0xA8, 0x18, 0x14,
0x5F, 0xC1, 0xB8, 0xBD, 0xA7, 0x3E, 0x53, 0x4C, 0x81, 0x70, 0x02, 0xB9, 0xF0, 0x44, 0xF2, 0x4A, 0xF5, 0x90, 0x9A, 0x9E, 0xB8, 0x6D, 0xDD, 0x8B, 0x23, 0xC3, 0x21, 0xBD, 0xA5, 0xC7, 0x3C, 0x45, 0xEA, 0xCC, 0x41, 0xF5, 0xFF, 0xB5, 0x64, 0xFE, 0xED, 0x25, 0x27, 0x98, 0xE7, 0xBF, 0x70, 0x9C, 0x4E, 0x9B, 0x44, 0x53,
0x72, 0x61, 0x19, 0x21, 0x49, 0x06, 0x87, 0xC8, 0x16, 0xC4, 0xCD, 0xB9, 0x17, 0x92, 0x54, 0xC4, 0xB0, 0x5D, 0x3B, 0xB4, 0x0D, 0xE7, 0x7D, 0x6C, 0x8D, 0x5F, 0x4E, 0x3B, 0x73, 0x1B, 0x8F, 0x4C, 0x00, 0x75, 0x81, 0x3A, 0xC0, 0xE3, 0x44, 0xE6, 0xA3, 0x58, 0x85, 0xE4, 0x3B, 0xC6, 0x5D, 0xE8, 0xAE, 0x39, 0x33, 0xB2,
0xD4, 0xFD, 0x15, 0x3E, 0x5E, 0xC3, 0xFF, 0x33, 0x73, 0x10, 0xD5, 0xC6, 0xCD, 0x19, 0x0B, 0x89, 0xE2, 0x41, 0x6C, 0x25, 0xB2, 0x1C, 0x12, 0x61, 0x81, 0xDF, 0x83, 0x7E, 0xE4, 0xF0, 0xDC, 0x4F, 0xEC, 0x16, 0xA7, 0x18, 0x9C, 0x27, 0xB4, 0x61, 0x99, 0xC0, 0x82, 0xA4, 0x0E, 0xEB, 0x23, 0xE7, 0x2B, 0x39, 0x90, 0x3B,
0x17, 0x3D, 0xDD, 0xBF, 0x4F, 0x8F, 0xEE, 0x45, 0x4A, 0x13, 0xD1, 0xE3, 0x5C, 0x8B, 0x6F, 0xA4, 0x14, 0x9C, 0xC5, 0x9D, 0xC2, 0x21, 0x90, 0x4B, 0x18, 0x98, 0x3C, 0xD2, 0x64, 0x4A, 0x58, 0xC0, 0xA5, 0x93, 0x34, 0x31, 0xFF, 0x14, 0x8C, 0x68, 0x54, 0x96, 0xFD, 0xA7, 0x09, 0x81, 0x48, 0x04, 0x25, 0xF1, 0xA2, 0xCE,
0x6F, 0x45, 0xEA, 0x5D, 0x40, 0xB5, 0x89, 0xB6, 0xF0, 0xFF, 0x51, 0xFF, 0x2B, 0x8A, 0xFA, 0x5F, 0x2E, 0xC4, 0x17, 0xD8, 0x76, 0xCA, 0x03, 0x58, 0x3B, 0xF5, 0x2B, 0x53, 0x43, 0x26, 0x3C, 0x81, 0xE0, 0x44, 0x62, 0x19, 0x96, 0x0B, 0x04, 0x43, 0x58, 0xDA, 0x38, 0xC4, 0xB2, 0x10, 0xDD, 0x9C, 0x7B, 0x21, 0x74, 0x23,
0xB4, 0xE0, 0xC3, 0x06, 0x54, 0x3B, 0xCA, 0x79, 0x3F, 0x1E, 0xBA, 0x63, 0xFB, 0x9A, 0xD9, 0x16, 0x23, 0x3A, 0xB6, 0x2C, 0x94, 0x11, 0x4E, 0xDF, 0xE3, 0x04, 0x65, 0x31, 0x6C, 0x17, 0x0F, 0xF7, 0x31, 0x1D, 0x5E, 0x6A, 0x03, 0xEA, 0xAF, 0xD1, 0xF1, 0x06, 0xFA, 0x9F, 0x8B, 0x41, 0xD4, 0x1B, 0x37, 0xE7, 0x24, 0x24,
0x37, 0xCE, 0x76, 0x37, 0x1B, 0x6C, 0x6D, 0x81, 0xC6, 0xE3, 0xDB, 0xB8, 0x24, 0x99, 0x79, 0xAB, 0xA2, 0x96, 0x3E, 0x44, 0x9D, 0x6B, 0x92, 0x6A, 0x1C, 0xB5, 0xB6, 0x07, 0x89, 0x94, 0xA8, 0x74, 0x48, 0x99, 0x05, 0x79, 0x3F, 0xAA, 0xE9, 0xD1, 0x23, 0x7E, 0x25, 0x53, 0x15, 0xEB, 0x71, 0x2E, 0xB2, 0x08, 0xCE, 0xA4,
0xE6, 0xDF, 0x6A, 0x2F, 0xED, 0x5A, 0x7C, 0xD3, 0x9D, 0x27, 0x03, 0x00, 0x88, 0xBE, 0xF2, 0x7E, 0xAE, 0x85, 0x3E, 0xF5, 0x1A, 0x09, 0x2D, 0x71, 0xCB, 0xB0, 0x19, 0x9C, 0x87, 0x9D, 0x81, 0x11, 0x01, 0x57, 0x20, 0x08, 0xDD, 0x8A, 0xD9, 0xBB, 0x80, 0xB7, 0x49, 0xB2, 0xF0, 0xFF, 0xAD, 0xFE, 0x67, 0x64, 0xF5, 0x1F,
0x0A, 0xB2, 0x0A, 0x11, 0xD3, 0x32, 0x2F, 0x89, 0x99, 0x85, 0xD2, 0x1A, 0x41, 0x56, 0xBE, 0x0C, 0x2D, 0x92, 0xA7, 0xE7, 0x9A, 0xBB, 0x74, 0x1C, 0xB0, 0x41, 0xCE, 0xC4, 0xD7, 0x8F, 0xC2, 0x89, 0x72, 0xFA, 0xB0, 0xE0, 0x1E, 0xE2, 0x85, 0xFA, 0xB8, 0x9F, 0x34, 0xDD, 0x89, 0x7C, 0x61, 0xDA, 0x40, 0x20, 0x9D, 0x48,
0x64, 0x01, 0x6C, 0x50, 0xBE, 0xAB, 0x0C, 0xD1, 0xFF, 0xB9, 0xF1, 0x2C, 0xA2, 0x3C, 0x21, 0x81, 0x07, 0x0F, 0x92, 0xD8, 0x70, 0x91, 0x81, 0x95, 0xF1, 0x51, 0x16, 0xD1, 0x88, 0xC2, 0xF7, 0x14, 0xE0, 0xA6, 0x68, 0x77, 0xA7, 0x2D, 0xE6, 0x16, 0xB8, 0x3D, 0x26, 0x14, 0xA5, 0x4B, 0x32, 0xC3, 0x9C, 0x6D, 0x49, 0x49,
0x6F, 0x0C, 0xFE, 0xC2, 0x73, 0x27, 0xF6, 0x34, 0xCE, 0xB3, 0x9C, 0x24, 0x48, 0xD6, 0xF7, 0x13, 0x82, 0x97, 0x6A, 0x1C, 0x20, 0xC4, 0xB6, 0xA8, 0x80, 0xE8, 0x1F, 0x56, 0xE7, 0x8A, 0x65, 0x0A, 0xC7, 0xA5, 0xE5, 0xB3, 0xDA, 0x2B, 0xAB, 0x8E, 0x9E, 0xE9, 0x2E, 0x3B, 0x03, 0x64, 0x88, 0x9F, 0xF2, 0x7E, 0x8E, 0xC7,
0x9B, 0xFA, 0x32, 0xB3, 0xB1, 0x4F, 0xA8, 0xD5, 0x37, 0x09, 0x7F, 0x87, 0x57, 0x0B, 0xE4, 0x8F, 0xC6, 0x1C, 0x5F, 0x10, 0xF5, 0x4E, 0xD4, 0x95, 0x8C, 0x71, 0xC4, 0x71, 0xAD, 0x51, 0xC0, 0x32, 0xFE, 0x98, 0xE6, 0x3A, 0x68, 0x95, 0x02, 0xE6, 0x6E, 0x5E, 0x1A, 0xB2, 0x30, 0xA5, 0x0D, 0x8C, 0xAC, 0x9A, 0x8C, 0x12,
0x9A, 0xC0, 0x88, 0x8C, 0xA5, 0xE8, 0xC6, 0x1F, 0xC5, 0x87, 0x6F, 0xB3, 0xE1, 0x6F, 0xD4, 0x91, 0xBF, 0x60, 0x48, 0x3B, 0x07, 0x34, 0xF8, 0xC6, 0x1D, 0x29, 0xE9, 0xBF, 0xE7, 0x86, 0xBB, 0x74, 0x1C, 0xC8, 0x20, 0x35, 0x01, 0x32, 0xA8, 0xDE, 0xD5, 0x9A, 0xE8, 0xFF, 0x5C, 0x7B, 0x16, 0x63, 0x9E, 0xA2, 0xC0, 0xCE,
0xB5, 0x67, 0x6B, 0x03, 0x0A, 0x98, 0x83, 0x84, 0x76, 0x90, 0x45, 0x52, 0x48, 0xB9, 0x78, 0x9D, 0xA9, 0x42, 0x20, 0x14, 0xDD, 0x6A, 0x8C, 0xA2, 0xA0, 0xBD, 0x4E, 0x1A, 0x1A, 0x4D, 0x32, 0x08, 0x37, 0x3E, 0xAE, 0x4D, 0xE4, 0xC7, 0xCC, 0x0A, 0x66, 0x6E, 0x92, 0x7E, 0x56, 0xA2, 0x84, 0xCE, 0xFA, 0x51, 0x8A, 0xF0,
0xC2, 0x61, 0x2E, 0x2A, 0x2D, 0xB5, 0x97, 0x31, 0x83, 0x6E, 0xA4, 0x75, 0xFA, 0x02, 0x27, 0x80, 0xBE, 0xC0, 0xB5, 0xFB, 0x08, 0x73, 0x74, 0x21, 0x59, 0x54, 0x8A, 0x8F, 0x03, 0x44, 0xF0, 0x5C, 0x33, 0x22, 0x10, 0x3F, 0xA9, 0x2F, 0x17, 0x8D, 0x7D, 0xCE, 0xA5, 0xBE, 0xC3, 0xE4, 0x19, 0x5E, 0xBB, 0xA0, 0x3F, 0x09,
0x0A, 0x67, 0x8B, 0x26, 0x95, 0x65, 0xED, 0xB3, 0xD4, 0x17, 0xE7, 0xBD, 0xD8, 0xBC, 0xEE, 0x28, 0x13, 0xF4, 0x35, 0xF9, 0x93, 0x65, 0x72, 0xBC, 0xDE, 0x32, 0x73, 0x92, 0x90, 0x0E, 0x11, 0x64, 0x20, 0xE2, 0x28, 0x26, 0x05, 0x22, 0x35, 0x2C, 0x83, 0x37, 0xB7, 0x50, 0x04, 0x8F, 0x4E, 0xB3, 0x91, 0x27, 0xEA, 0xA8,
0x09, 0x14, 0xE0, 0x64, 0x8B, 0xAD, 0x69, 0xA4, 0xCB, 0xF1, 0xDC, 0x0E, 0x15, 0x08, 0x1B, 0xFD, 0x46, 0x9D, 0x7C, 0x22, 0xFB, 0x1E, 0x8B, 0x5F, 0xB4, 0xD4, 0x4F, 0x30, 0xE4, 0x95, 0x03, 0x0C, 0x9D, 0xB8, 0xA3, 0x74, 0xED, 0x79, 0xDF, 0x80, 0x67, 0x2C, 0x00, 0xC2, 0x2B, 0xC8, 0x03, 0x29, 0xC5, 0x3C, 0x3A, 0xCE,
0x06, 0x44, 0x89, 0x49, 0x72, 0xFA, 0xDA, 0x7C, 0xCF, 0x79, 0x72, 0x6D, 0xF8, 0x38, 0xF5, 0x8D, 0x0A, 0x4E, 0x2D, 0xC9, 0x30, 0x14, 0x6C, 0x2D, 0x91, 0xA2, 0x54, 0x43, 0x10, 0x0E, 0xEE, 0x7A, 0x44, 0xA4, 0xE0, 0xB5, 0xE2, 0xB2, 0x10, 0x94, 0x91, 0xD9, 0xCB, 0x98, 0x03, 0x37, 0xC4, 0xA3, 0xD7, 0x23, 0x98, 0xC8,
0x48, 0xAE, 0x26, 0x8A, 0x15, 0xBC, 0x64, 0x65, 0x2E, 0x2F, 0x61, 0x7D, 0xF2, 0x09, 0xB4, 0x0B, 0x70, 0xAA, 0x41, 0xFB, 0xFE, 0x2F, 0x8A, 0xE2, 0x56, 0x9B, 0xFA, 0x86, 0xE6, 0xEE, 0x63, 0xC8, 0x71, 0x42, 0xDA, 0xA9, 0xCC, 0x05, 0x95, 0x55, 0xEE, 0x8B, 0xAE, 0x2F, 0xE9, 0xF7, 0x12, 0xF1, 0xBA, 0xA7, 0x9E, 0xE0,
0x80, 0xEF, 0x07, 0x33, 0x62, 0xD1, 0x85, 0x82, 0x10, 0xBF, 0xF2, 0x87, 0xCB, 0x30, 0x89, 0xD5, 0xC3, 0xDB, 0x4F, 0x91, 0x85, 0x44, 0xA9, 0xA3, 0x74, 0xF0, 0x90, 0xBA, 0x01, 0xAD, 0xBD, 0x5E, 0xB3, 0x13, 0x28, 0x81, 0x29, 0x26, 0x5B, 0xB3, 0x40, 0x97, 0xA3, 0xB9, 0x9D, 0x8C, 0x28, 0x12, 0x80, 0x6D, 0x4C, 0xFA,
0x40, 0x17, 0x99, 0x8B, 0xC7, 0x0D, 0xAC, 0xDC, 0x56, 0x4C, 0x15, 0xE1, 0x8F, 0xC5, 0x05, 0xA7, 0xCB, 0x3E, 0x4D, 0xFE, 0x13, 0x54, 0x23, 0x29, 0x33, 0x6D, 0x35, 0xE8, 0x4F, 0x54, 0xDD, 0x13, 0xF6, 0x8B, 0xBB, 0xDA, 0x00, 0x94, 0x0A, 0x92, 0xF3, 0x63, 0xF3, 0x3D, 0xE7, 0x39, 0xE6, 0x1B, 0x29, 0xF4, 0x4D, 0x0C,
0xF1, 0x61, 0x0F, 0x68, 0xC0, 0x12, 0x01, 0x8C, 0xE9, 0x08, 0x07, 0x37, 0x4C, 0x4C, 0x09, 0x09, 0x33, 0x66, 0x38, 0x2F, 0xE5, 0x2B, 0xB0, 0x3C, 0xAB, 0x47, 0xCE, 0x4C, 0xC9, 0x08, 0x10, 0x62, 0x2E, 0x91, 0x83, 0x48, 0xCF, 0x26, 0x46, 0x33, 0x78, 0x69, 0xCF, 0x5C, 0x9D, 0xC2, 0xFA, 0xD5, 0x67, 0x28, 0x07, 0x04,
0xB2, 0xF8, 0x23, 0x80, 0xC1, 0x4A, 0xEB, 0x5E, 0x24, 0x86, 0x2C, 0x0E, 0xEC, 0x40, 0x42, 0x90, 0x10, 0x51, 0x9E, 0x98, 0x92, 0x3B, 0x8B, 0x1B, 0x71, 0xFC, 0xB0, 0x96, 0xF7, 0xAB, 0x3F, 0x38, 0x88, 0x3B, 0x63, 0x02, 0xDD, 0x0F, 0x66, 0xCC, 0xE2, 0x13, 0x05, 0x98, 0x2A, 0x3C, 0xC5, 0xAD, 0xCC, 0xEC, 0xE1, 0xDD,
0xC8, 0x1D, 0x6B, 0x69, 0x72, 0xFE, 0xA3, 0xC9, 0x8F, 0xF6, 0xFB, 0x3B, 0x35, 0x99, 0x7F, 0xF1, 0x79, 0x11, 0x29, 0x0E, 0xB5, 0xEA, 0x90, 0x93, 0x19, 0xF2, 0xAF, 0xB1, 0x84, 0xC4, 0x5D, 0x47, 0xE5, 0xE0, 0x81, 0x4F, 0x32, 0x97, 0x8F, 0x1B, 0x84, 0xBB, 0xAD, 0x09, 0x15, 0xC5, 0x1A, 0x87, 0x1C, 0xE2, 0xD1, 0xE4,
0x95, 0x90, 0x72, 0x87, 0xC5, 0xAF, 0xF8, 0x41, 0x78, 0xA3, 0xF8, 0xA0, 0xC4, 0xCC, 0x0C, 0xFA, 0xE4, 0x0A, 0x2D, 0x62, 0x30, 0x71, 0x96, 0x1C, 0x83, 0x49, 0xDF, 0xC2, 0x1B, 0xC9, 0x88, 0x29, 0x3C, 0x6F, 0x3E, 0xEC, 0x01, 0x07, 0xAC, 0xC8, 0x80, 0x09, 0x1E, 0xD1, 0xE0, 0x46, 0x90, 0x29, 0x45, 0x61, 0xD1, 0x18,
0xE2, 0x51, 0x56, 0x67, 0xB9, 0xE2, 0x62, 0xD6, 0xC5, 0xDC, 0xF5, 0xDA, 0x26, 0xAB, 0xC2, 0xE9, 0x50, 0xFA, 0x74, 0x00, 0x95, 0x57, 0xDC, 0xE0, 0x22, 0x7A, 0xD9, 0x96, 0xEA, 0x19, 0x58, 0xD9, 0xAB, 0xC7, 0xB4, 0xF8, 0x2D, 0xC0, 0x60, 0x45, 0x14, 0x96, 0x53, 0x92, 0x59, 0x18, 0x54, 0x81, 0x02, 0x20, 0x45, 0xA2,
0x1A, 0xA4, 0xB4, 0x65, 0xFC, 0xE4, 0x88, 0x84, 0x83, 0x3E, 0x16, 0x52, 0x6D, 0xB5, 0x82, 0x82, 0x26, 0x9A, 0x22, 0xD6, 0xF2, 0xB6, 0x89, 0xCD, 0xDC, 0x52, 0x22, 0x32, 0xA5, 0x77, 0x16, 0x4B, 0x7A, 0x95, 0x8E, 0xB5, 0x22, 0x6B, 0x1C, 0x0D, 0x49, 0x04, 0xE3, 0xD8, 0x3F, 0xB8, 0xC8, 0xFC, 0x53, 0xC6, 0x45, 0x14,
0x7B, 0xEA, 0xB9, 0xE5, 0xCD, 0xE5, 0xA7, 0x48, 0xE4, 0xDE, 0x8D, 0xEB, 0x0A, 0x8D, 0xE3, 0x47, 0x5F, 0xA4, 0xA6, 0x22, 0x1F, 0x15, 0x35, 0x8C, 0xDE, 0x3E, 0x3B, 0x14, 0x5D, 0xD6, 0x42, 0x27, 0x37, 0xE4, 0xAB, 0x40, 0xE5, 0x1E, 0x9D, 0x5F, 0x65, 0xEC, 0xC7, 0xE1, 0xC1, 0xC5, 0xCC, 0x0D, 0xFA, 0x54, 0x0F, 0x4D,
0xD0, 0x90, 0x34, 0x14, 0x84, 0xDE, 0x82, 0xED, 0x42, 0x4F, 0x05, 0x92, 0x15, 0x9D, 0x7D, 0xEC, 0xE2, 0xFD, 0x26, 0x2F, 0x5A, 0x64, 0xE9, 0x24, 0x97, 0x18, 0x3F, 0xC2, 0x4B, 0x8F, 0xC1, 0x14, 0xF2, 0x68, 0xBD, 0xB3, 0x42, 0x72, 0x09, 0xE9, 0x12, 0xEA, 0x7A, 0x65, 0x33, 0xF2, 0xAE, 0x4A, 0x02, 0x95, 0xB4, 0x3A,
0xE4, 0xDD, 0xEC, 0x8D, 0x64, 0xC5, 0x49, 0xA7, 0x2F, 0x95, 0x3D, 0xA0, 0xAE, 0xBB, 0x81, 0x6F, 0xB2, 0x70, 0x1E, 0x3D, 0x28, 0x82, 0xD1, 0x06, 0x0F, 0x3F, 0x80, 0xD3, 0x2B, 0x29, 0x40, 0xAB, 0x10, 0xC4, 0x6A, 0x90, 0xCA, 0x92, 0xC9, 0xCA, 0x11, 0x05, 0x06, 0x5F, 0x16, 0x52, 0x6F, 0xB6, 0x82, 0x67, 0x4D, 0x15,
0xB1, 0x3E, 0x31, 0xFD, 0x26, 0xAC, 0xA2, 0x55, 0x4A, 0x8B, 0xB7, 0x48, 0x93, 0x12, 0x4F, 0xF1, 0x30, 0x0F, 0x0D, 0x30, 0x8E, 0xF3, 0x37, 0x01, 0xDC, 0xD3, 0x25, 0xA8, 0xD5, 0x65, 0x53, 0x9B, 0xB9, 0x95, 0xF2, 0x5C, 0x73, 0xAB, 0x8B, 0xAB, 0xAB, 0x48, 0xD4, 0xDA, 0xB1, 0x28, 0xA5, 0x46, 0x08, 0x39, 0x5E, 0xFA,
0x64, 0x8B, 0xC9, 0x09, 0xAB, 0xB1, 0x98, 0x78, 0x1C, 0x4B, 0x12, 0x2F, 0xE5, 0x22, 0xF6, 0x94, 0xD1, 0x93, 0x8F, 0xE6, 0x18, 0xD2, 0xCF, 0x73, 0x70, 0x1F, 0xA2, 0x14, 0x8D, 0xFA, 0xA3, 0xB2, 0x82, 0xF1, 0xE9, 0x03, 0x28, 0xA7, 0xB4, 0xD8, 0x5B, 0x88, 0x5D, 0xE8, 0x19, 0x43, 0x82, 0xE5, 0xE0, 0x88, 0x3E, 0xC2,
0xF0, 0xD7, 0x55, 0xB3, 0x75, 0x5B, 0xC4, 0x0E, 0x13, 0x57, 0x6C, 0x3B, 0x55, 0x89, 0xA0, 0x81, 0x5E, 0x8D, 0x2D, 0x21, 0x1F, 0x35, 0x3A, 0xD9, 0xE4, 0x2F, 0x8C, 0x79, 0x8B, 0x8E, 0x74, 0x5A, 0x54, 0xEA, 0xA4, 0xA7, 0x18, 0xD4, 0xDD, 0xEC, 0x64, 0xE1, 0xD5, 0x98, 0x1F, 0xDD, 0xD2, 0xD6, 0x40, 0xBC, 0xEE, 0x63,
0x5D, 0x31, 0x68, 0xC8, 0x13, 0xEC, 0x79, 0x56, 0xB4, 0xAC, 0x6E, 0x4C, 0x20, 0x88, 0x43, 0x78, 0x86, 0xD8, 0x54, 0x69, 0x28, 0xD9, 0x85, 0x00, 0x88, 0x68, 0x41, 0x8C, 0x30, 0xE7, 0xF1, 0x42, 0x11, 0xB2, 0x36, 0x74, 0xF9, 0xAB, 0xA8, 0x93, 0xBA, 0xDF, 0x94, 0x54, 0x08, 0x29, 0x2B, 0xC3, 0xC5, 0x5B, 0x64, 0x51,
0x8F, 0xFC, 0x20, 0x87, 0x72, 0x7C, 0xB0, 0xC8, 0x34, 0xDC, 0x6B, 0x23, 0x90, 0xED, 0xDD, 0x04, 0x5C, 0x21, 0xE1, 0x26, 0xDF, 0xD4, 0x19, 0x80, 0xCE, 0x6D, 0x49, 0x42, 0x3C, 0x42, 0x43, 0x03, 0xB2, 0xE3, 0xF2, 0x24, 0x00, 0x0A, 0xC1, 0x27, 0x12, 0x53, 0x60, 0x56, 0x13, 0x32, 0x49, 0x3B, 0x96, 0x46, 0x5E, 0xE9,
0x97, 0x9D, 0x75, 0xE9, 0x4E, 0x0C, 0x2C, 0xED, 0x51, 0x7D, 0xF4, 0x24, 0x71, 0x9B, 0x7D, 0xF8, 0x55, 0xDC, 0x67, 0x67, 0x0C, 0x20, 0xEA, 0x05, 0x3F, 0xB5, 0x8B, 0xC4, 0x2A, 0xA3, 0xE7, 0x1F, 0xC7, 0x23, 0x74, 0x3F, 0xAF, 0xA1, 0x3E, 0xD0, 0xD7, 0xEB, 0xCE, 0x2E, 0xFA, 0xA0, 0xE2, 0xE6, 0x08, 0x72, 0x25, 0xB2,
0xDA, 0x35, 0x16, 0x0B, 0xE2, 0x5A, 0x17, 0x33, 0xDB, 0xB1, 0x9A, 0xAC, 0x69, 0xF4, 0xEC, 0x89, 0xCF, 0xBE, 0xD2, 0x4E, 0x9F, 0x73, 0xE0, 0x58, 0xC1, 0x11, 0x53, 0x17, 0x09, 0x6E, 0xE8, 0xF5, 0xD0, 0x52, 0xF4, 0xD1, 0x83, 0x53, 0x45, 0xFE, 0x82, 0x8F, 0x38, 0xC8, 0x6D, 0x2E, 0x22, 0x2C, 0x39, 0xEA, 0x19, 0xD2,
0x2F, 0xD8, 0xB5, 0x66, 0x63, 0x60, 0x89, 0xC7, 0x54, 0x38, 0x58, 0xD7, 0xF2, 0x8D, 0xD5, 0x2B, 0x7C, 0x0C, 0x8E, 0x6A, 0xB2, 0xDD, 0x6B, 0xF7, 0x38, 0x40, 0x0A, 0xBF, 0x31, 0x05, 0x20, 0x31, 0xE1, 0x39, 0x64, 0x33, 0xAE, 0xA1, 0x22, 0x17, 0x51, 0x86, 0x18, 0xF7, 0x58, 0x0F, 0x0A, 0x30, 0xA7, 0x85, 0x45, 0x63,
0x08, 0x95, 0x8E, 0x90, 0x16, 0xE2, 0xC5, 0xC7, 0x85, 0x7E, 0x7D, 0xF7, 0x3A, 0xC6, 0x1B, 0x7A, 0xCF, 0xD9, 0xA5, 0x66, 0x83, 0x3E, 0x47, 0x77, 0xF0, 0xC7, 0xD3, 0xBD, 0x32, 0x03, 0x55, 0xDE, 0xC7, 0x80, 0x15, 0x32, 0x29, 0xF2, 0x1D, 0xAC, 0xF7, 0xA2, 0x0C, 0x2D, 0x29, 0xBB, 0xE2, 0x5F, 0x9F, 0xEF, 0xC4, 0x20,
0x02, 0x57, 0x5F, 0x45, 0x8C, 0x97, 0xC4, 0x88, 0x8F, 0xC8, 0xA1, 0xA8, 0x18, 0xF8, 0x0F, 0x32, 0x52, 0xB8, 0xEC, 0x42, 0x90, 0x46, 0x4B, 0x6D, 0xAA, 0x9A, 0xD7, 0x9E, 0xD8, 0xC7, 0xFF, 0xA4, 0x6E, 0x8B, 0x07, 0xBF, 0x46, 0xF7, 0xC5, 0x3F, 0x91, 0x21, 0xAE, 0x85, 0x1E, 0xB5, 0xDA, 0x37, 0x17, 0x0B, 0xCC, 0xB0,
0x8A, 0x07, 0xE8, 0xB0, 0x39, 0x72, 0xF2, 0x23, 0x8C, 0xF8, 0xFE, 0x49, 0x0C, 0x1F, 0xF4, 0xF1, 0x50, 0x6B, 0xEA, 0x3D, 0xFD, 0x61, 0x93, 0x5E, 0x7F, 0x03, 0xBF, 0x9A, 0xD9, 0x8E, 0xD5, 0x11, 0x45, 0xE3, 0xB5, 0x27, 0xC0, 0x8C, 0x56, 0x51, 0xF1, 0x75, 0x0E, 0x12, 0x2A, 0x14, 0x91, 0xAF, 0xAC, 0xC2, 0xEA, 0xA0,
0xEC, 0xCC, 0x9A, 0xAD, 0x87, 0xFD, 0x56, 0x0B, 0x3F, 0xAC, 0x6E, 0x92, 0x66, 0x67, 0x20, 0x40, 0xE0, 0x0F, 0x85, 0x61, 0x9D, 0xE4, 0xDF, 0x7F, 0xE9, 0x2D, 0xF6, 0x00, 0x43, 0x35, 0x59, 0xA5, 0x48, 0xEA, 0x5B, 0x38, 0x04, 0xED, 0x1B, 0x5A, 0x06, 0xC7, 0x39, 0xD9, 0x3D, 0xE8, 0x1E, 0xC8, 0x0C, 0x21, 0x3C, 0x9D,
0xFD, 0xA0, 0x08, 0xE0, 0x8D, 0xED, 0x62, 0x1A, 0x2C, 0x02, 0xB9, 0x22, 0x20, 0x58, 0x2B, 0x03, 0xA2, 0xD3, 0xE7, 0xFE, 0xC4, 0xE0, 0x8B, 0x3E, 0x0E, 0x05, 0x88, 0x5A, 0x04, 0x97, 0x96, 0x0B, 0xFD, 0xF4, 0x03, 0xC9, 0xB8, 0x84, 0x1B, 0x7A, 0x90, 0x2F, 0x4A, 0xEA, 0xB4, 0xF9, 0x3A, 0xBA, 0xFD, 0xDF, 0x16, 0x34,
0xF5, 0xB6, 0x54, 0x69, 0xF3, 0x62, 0x8F, 0xE0, 0xE4, 0x71, 0x53, 0x2C, 0xE7, 0xDC, 0xCA, 0xC6, 0x11, 0x97, 0x53, 0x7C, 0xF8, 0x9D, 0xD1, 0x7F, 0x2A, 0xD6, 0xFB, 0x1A, 0xD9, 0x78, 0x85, 0x8C, 0xB4, 0x44, 0x8E, 0x48, 0x25, 0xB2, 0x47, 0x19, 0x38, 0x50, 0x24, 0xBB, 0x30, 0xD2, 0x24, 0xA9, 0x91, 0x9E, 0xA7, 0x8A,
0xF0, 0x02, 0x25, 0x33, 0xAD, 0x5C, 0xA5, 0x06, 0x54, 0x16, 0x37, 0x85, 0xC5, 0x60, 0x72, 0xEE, 0x35, 0x3D, 0xEC, 0x4C, 0x16, 0x7E, 0x17, 0x4B, 0x70, 0xCF, 0x46, 0x0B, 0xE8, 0xA8, 0x38, 0xB5, 0xE4, 0x6B, 0x8C, 0xF8, 0xFE, 0xCE, 0x4C, 0x1F, 0xFC, 0xD8, 0x33, 0x3A, 0xD8, 0x56, 0xB0, 0xD7, 0xE1, 0xE9, 0xEF, 0xD1,
0xB9, 0x08, 0x86, 0xEC, 0x1A, 0x8E, 0xC1, 0xA2, 0xA8, 0x0D, 0x63, 0xB2, 0xA2, 0x54, 0x02, 0xB7, 0xA5, 0xE4, 0xC3, 0x07, 0x70, 0x25, 0x0D, 0xA4, 0xD7, 0xED, 0x9C, 0x59, 0x67, 0x77, 0xEF, 0x70, 0x77, 0x97, 0x1E, 0xAC, 0x3E, 0x66, 0x9D, 0xDE, 0x20, 0xCA, 0x82, 0x1F, 0x9E, 0x47, 0x54, 0x52, 0x7C, 0xFF, 0xAD, 0x87,
0x4A, 0x6D, 0xA5, 0x81, 0x61, 0x61, 0xB2, 0x4E, 0xBF, 0x20, 0x96, 0xA2, 0x00, 0xAC, 0x59, 0xCE, 0xE5, 0x79, 0x0B, 0xCE, 0x3F, 0xC0, 0xB5, 0xA2, 0x78, 0x85, 0x67, 0x08, 0x97, 0x65, 0x78, 0x6F, 0xBB, 0xD4, 0x0D, 0x96, 0x65, 0xB9, 0x64, 0x20, 0xAC, 0x95, 0xCB, 0xD2, 0xE2, 0xEB, 0xFE, 0xA2, 0xC1, 0x17, 0x5F, 0x0E,
0x8D, 0xF8, 0x98, 0x49, 0x8A, 0x56, 0x39, 0x23, 0xDD, 0xEC, 0x28, 0x37, 0x15, 0xC6, 0xF2, 0x46, 0xB7, 0xD9, 0x91, 0xED, 0xAD, 0x64, 0x20, 0xE2, 0xC5, 0xDB, 0x05, 0x7F, 0x5B, 0xF1, 0xB4, 0xA5, 0xB3, 0x87, 0x35, 0x50, 0x9E, 0x8F, 0x1B, 0x6A, 0x28, 0x43, 0x92, 0x3B, 0x71, 0xA7, 0xE4, 0xF0, 0x3B, 0xC7, 0xFF, 0x8C,
0xB1, 0x08, 0x49, 0xB1, 0xBC, 0x89, 0x2C, 0x6F, 0x31, 0xC2, 0x2F, 0x69, 0x21, 0xBF, 0x1F, 0x9C, 0x89, 0x8B, 0x54, 0x14, 0x17, 0xE1, 0xE2, 0xC2, 0x06, 0xF1, 0xAD, 0x91, 0x0E, 0x4A, 0x2E, 0xAC, 0x5C, 0xC7, 0x07, 0xD4, 0x3A, 0x37, 0xA5, 0xCE, 0x60, 0x3A, 0xF6, 0x9A, 0x1D, 0x76, 0xA6, 0x1D, 0xBF, 0x57, 0x4B, 0xA8,
0xF0, 0xB2, 0x7C, 0xBA, 0x21, 0xB2, 0xFF, 0xDF, 0x9E, 0xC5, 0x9C, 0xAD, 0xC6, 0x85, 0x74, 0xF2, 0xE1, 0xBC, 0xC4, 0x5E, 0x71, 0x83, 0xC4, 0x47, 0x44, 0x18, 0xE7, 0x3C, 0x32, 0x86, 0x22, 0x8D, 0xC6, 0x60, 0xB1, 0xD5, 0xC6, 0x98, 0xAC, 0xAC, 0x2B, 0xC1, 0x6D, 0xA5, 0xF3, 0x91, 0x03, 0xB8, 0x8A, 0x02, 0xCA, 0x71,
0x5B, 0xAB, 0x71, 0x35, 0xB6, 0xC4, 0x74, 0x00, 0x36, 0x88, 0xD9, 0x52, 0x4F, 0x1A, 0x08, 0x56, 0x9E, 0x93, 0x90, 0xEF, 0x60, 0x33, 0x5C, 0x4B, 0x8B, 0x3E, 0xBB, 0x4A, 0x59, 0x65, 0x60, 0x58, 0xDA, 0x59, 0x67, 0x0F, 0x88, 0xE5, 0x20, 0x00, 0x35, 0xDF, 0x72, 0x35, 0x6E, 0x21, 0xDB, 0x8F, 0x7C, 0x82, 0x00, 0x64,
0x7B, 0x1B, 0x11, 0x1B, 0x5D, 0x29, 0xA2, 0x39, 0x02, 0x62, 0x95, 0x57, 0x74, 0x5A, 0x89, 0xEC, 0x08, 0x3A, 0x36, 0xE1, 0x18, 0x81, 0x98, 0xAA, 0x38, 0x4A, 0xAF, 0xA8, 0x90, 0x1C, 0x33, 0x29, 0xD6, 0xAA, 0x60, 0xA4, 0x9B, 0x1F, 0xE5, 0x66, 0xCC, 0x58, 0xD1, 0xE8, 0x36, 0x3F, 0xB2, 0x8D, 0xCD, 0x1B, 0x68, 0x1D,
0x4F, 0x38, 0xB1, 0x1A, 0xDE, 0xA2, 0xD4, 0xA7, 0x2A, 0x75, 0x19, 0xC0, 0x87, 0x68, 0x39, 0x75, 0x01, 0x53, 0x02, 0x86, 0x99, 0x2A, 0x8B, 0x16, 0xEC, 0x77, 0x1D, 0xBC, 0x9D, 0x90, 0x90, 0x95, 0xD3, 0x9B, 0xA9, 0xF4, 0x8E, 0x46, 0xF8, 0x15, 0x25, 0xD4, 0xF3, 0xC1, 0x05, 0xB9, 0x58, 0x4D, 0x72, 0x31, 0x49, 0x2E,
0x76, 0x20, 0x9E, 0x20, 0x66, 0x67, 0xEC, 0x83, 0xE3, 0x67, 0x07, 0xB3, 0x70, 0xEE, 0x8C, 0xEE, 0xFD, 0x2F, 0xFC, 0x34, 0x4E, 0xF9, 0x5F, 0xA4, 0x00, 0x00 0x2A, 0x90, 0x0C, 0x2F, 0xAB, 0xC3, 0x0D, 0xB1, 0xFC, 0xFF, 0xF2, 0x32, 0x69, 0xD9, 0xF5, 0xA8, 0x14, 0x4F, 0x39, 0x9C, 0x57, 0x9A, 0x57, 0x5E, 0x20, 0xF5,
0x10, 0x11, 0xD1, 0xAC, 0xEB, 0x51, 0xBD, 0x66, 0x45, 0xE1, 0x00, 0x2A, 0x90, 0x34, 0x4B, 0x1F, 0x34, 0x88, 0x9A, 0xF2, 0x9A, 0x85, 0x72, 0x07, 0x9B, 0xE9,
0x5A, 0x46, 0xFC, 0xD8, 0xDB, 0x18, 0xD9, 0x38, 0xA5, 0x0C, 0xE7, 0x38, 0x93, 0xF0, 0xBC, 0xE2, 0xBF, 0xB5, 0xD0, 0x8E, 0x73, 0x27, 0x22, 0x9C, 0x00, 0x88,
0x42, 0x15, 0x98, 0x5B, 0x48, 0x07, 0x9C, 0x84, 0x0F, 0x6F, 0x71, 0xEC, 0x33, 0x9E, 0xBA, 0x9A, 0x01, 0x87, 0x56, 0x7A, 0x53, 0x17, 0x90, 0x52, 0x79, 0x84,
0xA8, 0x0A, 0x6B, 0x11, 0xAF, 0x29, 0x96, 0x2B, 0x88, 0xC5, 0x3F, 0xF1, 0xC0, 0x71, 0x1C, 0x4C, 0x11, 0xCE, 0x9D, 0xE1, 0x17, 0xFF, 0x06, 0x6E, 0xDA, 0x6F,
0xC1, 0x5F, 0xA4, 0x00, 0x00
}; };
//File: index_ov3660.html.gz, Size: 8636 //File: index_ov3660.html.gz, Size: 8636

View file

@ -1,4 +1,4 @@
// Copyright 2023 Espressif Systems (Shanghai) PTE LTD // Copyright 2025 Espressif Systems (Shanghai) PTE LTD
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -35,14 +35,11 @@
rmt_data_t my_data[256]; rmt_data_t my_data[256];
rmt_data_t data[256]; rmt_data_t data[256];
static EventGroupHandle_t events;
#define RMT_FREQ 10000000 // tick time is 100ns #define RMT_FREQ 10000000 // tick time is 100ns
#define RMT_NUM_EXCHANGED_DATA 30 #define RMT_NUM_EXCHANGED_DATA 32
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
events = xEventGroupCreate();
if (!rmtInit(RMT_TX_PIN, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, RMT_FREQ)) { if (!rmtInit(RMT_TX_PIN, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, RMT_FREQ)) {
Serial.println("init sender failed\n"); Serial.println("init sender failed\n");
@ -50,25 +47,41 @@ void setup() {
if (!rmtInit(RMT_RX_PIN, RMT_RX_MODE, RMT_MEM_RX, RMT_FREQ)) { if (!rmtInit(RMT_RX_PIN, RMT_RX_MODE, RMT_MEM_RX, RMT_FREQ)) {
Serial.println("init receiver failed\n"); Serial.println("init receiver failed\n");
} }
Serial.println();
Serial.println("RMT tick set to: 100ns");
// End of transmission shall be detected when line is idle for 2us = 20*100ns // End of transmission shall be detected when line is idle for 2us = 20*100ns
rmtSetRxMaxThreshold(RMT_RX_PIN, 20); rmtSetRxMaxThreshold(RMT_RX_PIN, 20);
// Disable Glitch filter // Disable Glitch filter
rmtSetRxMinThreshold(RMT_RX_PIN, 0); rmtSetRxMinThreshold(RMT_RX_PIN, 0);
Serial.println("real tick set to: 100ns"); // create multiple pulses with different width to be sent
Serial.printf("\nPlease connect GPIO %d to GPIO %d, now.\n", RMT_TX_PIN, RMT_RX_PIN); for (int i = 0; i < 255; i++) {
} data[i].level0 = 1; // HIGH
data[i].duration0 = 1 + 13 - (i % 13); // number of Tick on High
void loop() { data[i].level1 = 0; // LOW
// Init data data[i].duration1 = 1 + (i % 13); // number of Ticks on Low
int i;
for (i = 0; i < 255; i++) {
data[i].val = 0x80010001 + ((i % 13) << 16) + 13 - (i % 13);
my_data[i].val = 0; my_data[i].val = 0;
} }
data[255].val = 0; data[255].val = 0;
Serial.println();
Serial.println("====================================================================================================");
Serial.println("Preloaded Data that will sent (time in 0.1us):");
// Printout the received data plus the original values
for (int i = 0; i < RMT_NUM_EXCHANGED_DATA; i++) {
Serial.printf("%08lx=[%c 0x%02x|%c 0x%02x] ", data[i].val, data[i].level0 ? 'H' : 'L', data[i].duration0, data[i].level1 ? 'H' : 'L', data[i].duration1);
if (!((i + 1) % 4)) {
Serial.println();
}
}
Serial.println("====================================================================================================");
Serial.printf("Please connect GPIO %d to GPIO %d, now.", RMT_TX_PIN, RMT_RX_PIN);
Serial.println();
Serial.println();
}
void loop() {
// Start an async data read // Start an async data read
size_t rx_num_symbols = RMT_NUM_EXCHANGED_DATA; size_t rx_num_symbols = RMT_NUM_EXCHANGED_DATA;
rmtReadAsync(RMT_RX_PIN, my_data, &rx_num_symbols); rmtReadAsync(RMT_RX_PIN, my_data, &rx_num_symbols);
@ -84,13 +97,13 @@ void loop() {
Serial.printf("Got %d RMT symbols\n", rx_num_symbols); Serial.printf("Got %d RMT symbols\n", rx_num_symbols);
// Printout the received data plus the original values // Printout the received data plus the original values
for (i = 0; i < 60; i++) { for (int i = 0; i < RMT_NUM_EXCHANGED_DATA; i++) {
Serial.printf("%08lx=%08lx ", my_data[i].val, data[i].val); Serial.printf("%08lx=%08lx ", my_data[i].val, data[i].val);
if (!((i + 1) % 4)) { if (!((i + 1) % 4)) {
Serial.println(""); Serial.println();
} }
} }
Serial.println("\n"); Serial.println();
delay(500); delay(2000);
} }

View file

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
/** /**
* @brief This example demonstrates usage of RMT for receiving XJT D12 data * @brief This example demonstrates usage of RMT for receiving XJT D16 data
* *
* The output is the RMT data read and processed * The output is the RMT data read and processed
* *
@ -21,7 +21,7 @@
// //
// Note: This example uses a FrSKY device communication // Note: This example uses a FrSKY device communication
// using XJT D12 protocol // using XJT D16 protocol
// //
// ; 0 bit = 6us low/10us high // ; 0 bit = 6us low/10us high
// ; 1 bit = 14us low/10us high // ; 1 bit = 14us low/10us high

View file

@ -1,4 +1,4 @@
// Copyright 2023 Espressif Systems (Shanghai) PTE LTD // Copyright 2025 Espressif Systems (Shanghai) PTE LTD
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -13,16 +13,16 @@
// limitations under the License. // limitations under the License.
/** /**
* @brief This example demonstrate how to use RMT to just blink a regular LED (GPIO) @brief This example demonstrate how to use RMT to just blink a regular LED (GPIO)
* It uses all the different RMT Writing APIs to blink the LED by hardware, not being It uses all the different RMT Writing APIs to blink the LED by hardware, not being
* necessary the regular Blink code in Arduino. necessary the regular Blink code in Arduino.
*
* The output is the Blinking LED in the GPIO and a serial output describing what is The output is the Blinking LED in the GPIO and a serial output describing what is
* going on, along the execution. going on, along the execution.
*
* The circuit is just a LED and a resistor of 270 ohms connected to the GPIO The circuit is just a LED and a resistor of 270 ohms connected to the GPIO
* GPIO ---> resistor 270 ohms ---> + LED - ---> GND GPIO ---> resistor 270 ohms ---> + LED - ---> GND
*/ */
#define BLINK_GPIO 2 #define BLINK_GPIO 2
@ -232,7 +232,7 @@ void RMT_Mixed_Write_Blink() {
Serial.println("===> rmtWrite() (Blocking Mode) to Blink the LED."); Serial.println("===> rmtWrite() (Blocking Mode) to Blink the LED.");
Serial.println("Blinking at 500ms on + 500ms off :: 4 blinks"); Serial.println("Blinking at 500ms on + 500ms off :: 4 blinks");
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 1, RMT_WAIT_FOR_EVER)) {
Serial.println("===> rmtWrite Blink 0.5s Error!"); Serial.println("===> rmtWrite Blink 0.5s Error!");
} }
} }
@ -240,7 +240,7 @@ void RMT_Mixed_Write_Blink() {
Serial.println("===> rmtWriteAsync() (Non-Blocking Mode) to Blink the LED."); Serial.println("===> rmtWriteAsync() (Non-Blocking Mode) to Blink the LED.");
Serial.println("Blinking at 250ms on + 250ms off :: 5 blinks"); Serial.println("Blinking at 250ms on + 250ms off :: 5 blinks");
for (uint8_t i = 0; i < 5; i++) { for (uint8_t i = 0; i < 5; i++) {
if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2)) { if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 1)) {
Serial.println("===> rmtWrite Blink 0.25s Error!"); Serial.println("===> rmtWrite Blink 0.25s Error!");
} }
// wait (blocks) until all the data is sent out // wait (blocks) until all the data is sent out
@ -267,9 +267,11 @@ void RMT_Loop_Write_Blink() {
Serial.println("===> rmtWriteLooping Blink 0.25s Error!"); Serial.println("===> rmtWriteLooping Blink 0.25s Error!");
} }
delay(5000); delay(5000);
Serial.println("Blinking OFF for 2 seconds"); Serial.println("Blinking OFF for 2 seconds");
if (!rmtWriteLooping(BLINK_GPIO, NULL, 0)) { rmt_data_t blink_STOP_rmt_data[] = {{0, 0, 0, 0}};
Serial.println("===> rmtWriteLooping Blink OFF Error!"); if (!rmtWrite(BLINK_GPIO, blink_STOP_rmt_data, RMT_SYMBOLS_OF(blink_STOP_rmt_data), RMT_WAIT_FOR_EVER)) {
Serial.println("===> rmtWrite Blink STOP Error!");
} }
delay(2000); delay(2000);
} }
@ -278,19 +280,19 @@ void RMT_Single_Write_Blocking_Blink() {
Serial.println("Using RMT Writing and its Completion to blink an LED."); Serial.println("Using RMT Writing and its Completion to blink an LED.");
Serial.println("Blinking at 1s on + 1s off :: 2 blinks"); Serial.println("Blinking at 1s on + 1s off :: 2 blinks");
for (uint8_t i = 0; i < 2; i++) { for (uint8_t i = 0; i < 2; i++) {
if (!rmtWrite(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { if (!rmtWrite(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 1, RMT_WAIT_FOR_EVER)) {
Serial.println("===> rmtWrite Blink 1s Error!"); Serial.println("===> rmtWrite Blink 1s Error!");
} }
} }
Serial.println("Blinking at 500ms on + 500ms off :: 4 blinks"); Serial.println("Blinking at 500ms on + 500ms off :: 4 blinks");
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 1, RMT_WAIT_FOR_EVER)) {
Serial.println("===> rmtWrite Blink 0.5s Error!"); Serial.println("===> rmtWrite Blink 0.5s Error!");
} }
} }
Serial.println("Blinking at 250ms on + 250ms off :: 8 blinks"); Serial.println("Blinking at 250ms on + 250ms off :: 8 blinks");
for (uint8_t i = 0; i < 8; i++) { for (uint8_t i = 0; i < 8; i++) {
if (!rmtWrite(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { if (!rmtWrite(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 1, RMT_WAIT_FOR_EVER)) {
Serial.println("===> rmtWrite Blink 0.25s Error!"); Serial.println("===> rmtWrite Blink 0.25s Error!");
} }
} }
@ -302,7 +304,7 @@ void RMT_Write_Aync_Non_Blocking_Blink() {
Serial.println("Using RMT Async Writing and its Completion to blink an LED."); Serial.println("Using RMT Async Writing and its Completion to blink an LED.");
Serial.println("Blinking at 1s on + 1s off :: 5 blinks"); Serial.println("Blinking at 1s on + 1s off :: 5 blinks");
for (uint8_t i = 0; i < 5; i++) { for (uint8_t i = 0; i < 5; i++) {
if (!rmtWriteAsync(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 2)) { if (!rmtWriteAsync(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 1)) {
Serial.println("===> rmtWrite Blink 1s Error!"); Serial.println("===> rmtWrite Blink 1s Error!");
} }
// wait (blocks) until all the data is sent out // wait (blocks) until all the data is sent out
@ -310,7 +312,7 @@ void RMT_Write_Aync_Non_Blocking_Blink() {
} }
Serial.println("Blinking at 500ms on + 500ms off :: 5 blinks"); Serial.println("Blinking at 500ms on + 500ms off :: 5 blinks");
for (uint8_t i = 0; i < 5; i++) { for (uint8_t i = 0; i < 5; i++) {
if (!rmtWriteAsync(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2)) { if (!rmtWriteAsync(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 1)) {
Serial.println("===> rmtWrite Blink 0.5s Error!"); Serial.println("===> rmtWrite Blink 0.5s Error!");
} }
// wait (blocks) until all the data is sent out // wait (blocks) until all the data is sent out
@ -318,7 +320,7 @@ void RMT_Write_Aync_Non_Blocking_Blink() {
} }
Serial.println("Blinking at 250ms on + 250ms off :: 5 blinks"); Serial.println("Blinking at 250ms on + 250ms off :: 5 blinks");
for (uint8_t i = 0; i < 5; i++) { for (uint8_t i = 0; i < 5; i++) {
if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2)) { if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 1)) {
Serial.println("===> rmtWrite Blink 0.25s Error!"); Serial.println("===> rmtWrite Blink 0.25s Error!");
} }
// wait (blocks) until all the data is sent out // wait (blocks) until all the data is sent out
@ -345,7 +347,6 @@ void setup() {
RMT_Mixed_Write_Blink(); RMT_Mixed_Write_Blink();
Serial.println("End of Mixed Calls testing"); Serial.println("End of Mixed Calls testing");
delay(1000);
Serial.println("\n==============================="); Serial.println("\n===============================");
Serial.println("Starting a Blinking sequence..."); Serial.println("Starting a Blinking sequence...");

View file

@ -21,6 +21,15 @@
If UART receives less than 120 bytes, it will wait RX Timeout to understand that the bus is IDLE and If UART receives less than 120 bytes, it will wait RX Timeout to understand that the bus is IDLE and
then copy the data from the FIFO to the Arduino internal buffer, making it available to the Arduino API. then copy the data from the FIFO to the Arduino internal buffer, making it available to the Arduino API.
There is an important detail about how HardwareSerial works using ESP32 and ESP32-S2:
If the baud rate is lower than 250,000, it will select REF_TICK as clock source in order to avoid that
the baud rate may change when the CPU Frequency is changed. Default UART clock source is APB, which changes
when CPU clock source is also changed. But when it selects REF_TICK as UART clock source, RX Timeout is limited to 1.
Therefore, in order to change the ESP32/ESP32-S2 RX Timeout it is necessary to fix the UART Clock Source to APB.
In the case of the other SoC, such as ESP32-S3, C3, C6, H2 and P4, there is no such RX Timeout limitation.
Those will set the UART Source Clock as XTAL, which allows the baud rate to be high and it is steady, not
changing with the CPU Frequency.
*/ */
#include <Arduino.h> #include <Arduino.h>
@ -45,6 +54,12 @@ void setup() {
// UART1 will have its RX<->TX cross connected // UART1 will have its RX<->TX cross connected
// GPIO4 <--> GPIO5 using external wire // GPIO4 <--> GPIO5 using external wire
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
// UART_CLK_SRC_APB will allow higher values of RX Timeout
// default for ESP32 and ESP32-S2 is REF_TICK which limits the RX Timeout to 1
// setClockSource() must be called before begin()
Serial1.setClockSource(UART_CLK_SRC_APB);
#endif
Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3 Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3
#if USE_INTERNAL_PIN_LOOPBACK #if USE_INTERNAL_PIN_LOOPBACK
uart_internal_loopback(TEST_UART, RXPIN); uart_internal_loopback(TEST_UART, RXPIN);

View file

@ -5,20 +5,20 @@
void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout = false) void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout = false)
It is possible to register an UART callback function that will be called It is possible to register an UART callback function that will be called
every time that UART receives data and an associated interrupt is generated. every time that UART receives data and an associated UART interrupt is generated.
In summary, HardwareSerial::onReceive() works like an RX Interrupt callback, that can be adjusted In summary, HardwareSerial::onReceive() works like an RX Interrupt callback, that
using HardwareSerial::setRxFIFOFull() and HardwareSerial::setRxTimeout(). can be adjusted using HardwareSerial::setRxFIFOFull() and HardwareSerial::setRxTimeout().
OnReceive will be called, while receiving a stream of data, when every 120 bytes are received (default FIFO Full), In case that <onlyOnTimeout> is not changed or it is set to <false>, the callback function is
which may not help in case that the application needs to get all data at once before processing it. executed whenever any event happens first (FIFO Full or RX Timeout).
Therefore, a way to make it work is by detecting the end of a stream transmission. This can be based on a protocol OnReceive will be called when every 120 bytes are received(default FIFO Full),
or based on timeout with the UART line in idle (no data received - this is the case of this example). or when RX Timeout occurs after 1 UART symbol by default.
In some cases, it is necessary to wait for receiving all the data before processing it and parsing the This example demonstrates a way to create a String with all data received from UART0 only
UART input. This example demonstrates a way to create a String with all data received from UART0 and after RX Timeout. This example uses an RX timeout of about 3.5 Symbols as a way to know
signaling it using a Mutex for another task to process it. This example uses a timeout of 500ms as a way to when the reception of data has finished.
know when the reception of data has finished. In order to achieve it, the sketch sets <onlyOnTimeout> to <true>.
The onReceive() callback is called whenever the RX ISR is triggered. The onReceive() callback is called whenever the RX ISR is triggered.
It can occur because of two possible events: It can occur because of two possible events:
@ -34,90 +34,73 @@
2- UART RX Timeout: it happens, based on a timeout equivalent to a number of symbols at 2- UART RX Timeout: it happens, based on a timeout equivalent to a number of symbols at
the current baud rate. If the UART line is idle for this timeout, it will raise an interrupt. the current baud rate. If the UART line is idle for this timeout, it will raise an interrupt.
This time can be changed by HardwareSerial::setRxTimeout(uint8_t rxTimeout) This time can be changed by HardwareSerial::setRxTimeout(uint8_t rxTimeout).
<rxTimeout> is bound to the clock source.
In order to use it properly, ESP32 and ESP32-S2 shall set the UART Clock Source to APB.
When any of those two interrupts occur, IDF UART driver will copy FIFO data to its internal When any of those two interrupts occur, IDF UART driver will copy FIFO data to its internal
RingBuffer and then Arduino can read such data. At the same time, Arduino Layer will execute RingBuffer and then Arduino can read such data. At the same time, Arduino Layer will execute
the callback function defined with HardwareSerial::onReceive(). the callback function defined with HardwareSerial::onReceive().
<bool onlyOnTimeout> parameter (default false) can be used by the application to tell Arduino to <bool onlyOnTimeout> parameter can be used by the application to tell Arduino to only execute
only execute the callback when the second event above happens (Rx Timeout). At this time all the callback when Rx Timeout happens, by setting it to <true>.
received data will be available to be read by the Arduino application. But if the number of At this time all received data will be available to be read by the Arduino application.
received bytes is higher than the FIFO space, it will generate an error of FIFO overflow. The application shall set an appropriate RX buffer size using
In order to avoid such problem, the application shall set an appropriate RX buffer size using
HardwareSerial::setRxBufferSize(size_t new_size) before executing begin() for the Serial port. HardwareSerial::setRxBufferSize(size_t new_size) before executing begin() for the Serial port.
*/
// this will make UART0 work in any case (using or not USB) MODBUS timeout of 3.5 symbol is based on these documents:
#if ARDUINO_USB_CDC_ON_BOOT https://www.automation.com/en-us/articles/2012-1/introduction-to-modbus
#define UART0 Serial0 https://minimalmodbus.readthedocs.io/en/stable/serialcommunication.html
#else */
#define UART0 Serial
#endif
// global variable to keep the results from onReceive() // global variable to keep the results from onReceive()
String uart_buffer = ""; String uart_buffer = "";
// a pause of a half second in the UART transmission is considered the end of transmission. // The Modbus RTU standard prescribes a silent period corresponding to 3.5 characters between each
const uint32_t communicationTimeout_ms = 500; // message, to be able to figure out where one message ends and the next one starts.
const uint32_t modbusRxTimeoutLimit = 4;
const uint32_t baudrate = 19200;
// Create a mutex for the access to uart_buffer // UART_RX_IRQ will be executed as soon as data is received by the UART and an RX Timeout occurs
// only one task can read/write it at a certain time // This is a callback function executed from a high priority monitor task
SemaphoreHandle_t uart_buffer_Mutex = NULL; // All data will be buffered into RX Buffer, which may have its size set to whatever necessary
// UART_RX_IRQ will be executed as soon as data is received by the UART
// This is a callback function executed from a high priority
// task created when onReceive() is used
void UART0_RX_CB() { void UART0_RX_CB() {
// take the mutex, waits forever until loop() finishes its processing while (Serial0.available()) {
if (xSemaphoreTake(uart_buffer_Mutex, portMAX_DELAY)) { uart_buffer += (char)Serial0.read();
uint32_t now = millis(); // tracks timeout
while ((millis() - now) < communicationTimeout_ms) {
if (UART0.available()) {
uart_buffer += (char)UART0.read();
now = millis(); // reset the timer
}
}
// releases the mutex for data processing
xSemaphoreGive(uart_buffer_Mutex);
} }
} }
// setup() and loop() are functions executed by a low priority task // setup() and loop() are functions executed by a low priority task
// Therefore, there are 2 tasks running when using onReceive() // Therefore, there are 2 tasks running when using onReceive()
void setup() { void setup() {
UART0.begin(115200); // Using Serial0 will work in any case (using or not USB CDC on Boot)
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
// creates a mutex object to control access to uart_buffer // UART_CLK_SRC_APB will allow higher values of RX Timeout
uart_buffer_Mutex = xSemaphoreCreateMutex(); // default for ESP32 and ESP32-S2 is REF_TICK which limits the RX Timeout to 1
if (uart_buffer_Mutex == NULL) { // setClockSource() must be called before begin()
log_e("Error creating Mutex. Sketch will fail."); Serial0.setClockSource(UART_CLK_SRC_APB);
while (true) { #endif
UART0.println("Mutex error (NULL). Program halted."); // the amount of data received or waiting to be proessed shall not exceed this limit of 1024 bytes
delay(2000); Serial0.setRxBufferSize(1024); // default is 256 bytes
} Serial0.begin(baudrate); // default pins and default mode 8N1 (8 bits data, no parity bit, 1 stopbit)
} // set RX Timeout based on UART symbols ~ 3.5 symbols of 11 bits (MODBUS standard) ~= 2 ms at 19200
Serial0.setRxTimeout(modbusRxTimeoutLimit); // 4 symbols at 19200 8N1 is about 2.08 ms (40 bits)
UART0.onReceive(UART0_RX_CB); // sets the callback function // sets the callback function that will be executed only after RX Timeout
UART0.println("Send data to UART0 in order to activate the RX callback"); Serial0.onReceive(UART0_RX_CB, true);
Serial0.println("Send data using Serial Monitor in order to activate the RX callback");
} }
uint32_t counter = 0; uint32_t counter = 0;
void loop() { void loop() {
// String <uart_buffer> is filled by the UART Callback whenever data is received and RX Timeout occurs
if (uart_buffer.length() > 0) { if (uart_buffer.length() > 0) {
// signals that the onReceive function shall not change uart_buffer while processing // process the received data from Serial - example, just print it beside a counter
if (xSemaphoreTake(uart_buffer_Mutex, portMAX_DELAY)) { Serial0.print("[");
// process the received data from UART0 - example, just print it beside a counter Serial0.print(counter++);
UART0.print("["); Serial0.print("] [");
UART0.print(counter++); Serial0.print(uart_buffer.length());
UART0.print("] ["); Serial0.print(" bytes] ");
UART0.print(uart_buffer.length()); Serial0.println(uart_buffer);
UART0.print(" bytes] "); uart_buffer = ""; // reset uart_buffer for the next UART reading
UART0.println(uart_buffer);
uart_buffer = ""; // reset uart_buffer for the next UART reading
// releases the mutex for more data to be received
xSemaphoreGive(uart_buffer_Mutex);
}
} }
UART0.println("Sleeping for 1 second..."); delay(1);
delay(1000);
} }

View file

@ -1,5 +1,5 @@
name=ESP32 name=ESP32
version=3.1.1 version=3.2.0
author=Hristo Gochkov, Ivan Grokhtkov author=Hristo Gochkov, Ivan Grokhtkov
maintainer=Hristo Gochkov <hristo@espressif.com> maintainer=Hristo Gochkov <hristo@espressif.com>
sentence=ESP32 sketches examples sentence=ESP32 sketches examples

View file

@ -1,5 +1,5 @@
name=ESP_I2S name=ESP_I2S
version=3.1.1 version=3.2.0
author=me-no-dev author=me-no-dev
maintainer=me-no-dev maintainer=me-no-dev
sentence=Library for ESP I2S communication sentence=Library for ESP I2S communication

View file

@ -11,6 +11,12 @@
#include "mp3dec.h" #include "mp3dec.h"
#endif #endif
#if SOC_I2S_HW_VERSION_2
#undef I2S_STD_CLK_DEFAULT_CONFIG
#define I2S_STD_CLK_DEFAULT_CONFIG(rate) \
{ .sample_rate_hz = rate, .clk_src = I2S_CLK_SRC_DEFAULT, .ext_clk_freq_hz = 0, .mclk_multiple = I2S_MCLK_MULTIPLE_256, }
#endif
#define I2S_READ_CHUNK_SIZE 1920 #define I2S_READ_CHUNK_SIZE 1920
#define I2S_DEFAULT_CFG() \ #define I2S_DEFAULT_CFG() \

View file

@ -1,5 +1,5 @@
name=ESP_NOW name=ESP_NOW
version=3.1.1 version=3.2.0
author=me-no-dev author=me-no-dev
maintainer=P-R-O-C-H-Y maintainer=P-R-O-C-H-Y
sentence=Library for ESP_NOW sentence=Library for ESP_NOW

Some files were not shown because too many files have changed in this diff Show more