forked from espressif/esp-idf
Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
405b1986c2 | ||
|
|
7c42b55e45 | ||
|
|
f4022111c8 | ||
|
|
53dcd1202d | ||
|
|
ef2c0e8b3e | ||
|
|
7515dc97b6 | ||
|
|
a9c1820385 | ||
|
|
8fdf200932 | ||
|
|
4cde212817 | ||
|
|
6751373411 | ||
|
|
27fd353752 | ||
|
|
97603b1d59 | ||
|
|
32fd3a3215 | ||
|
|
d1c6eb9574 | ||
|
|
5ee2d3b90d | ||
|
|
8618b452f7 | ||
|
|
39fb5d7150 | ||
|
|
5dafcf9363 | ||
|
|
3f72a12d97 | ||
|
|
af4f2ace84 | ||
|
|
e8ad0415cc | ||
|
|
ac253274a0 | ||
|
|
972107fbc9 | ||
|
|
5e9267f846 | ||
|
|
cfed7c84ce | ||
|
|
3870836a90 | ||
|
|
19f319a55d | ||
|
|
0806617971 | ||
|
|
4f346169ff | ||
|
|
00b895680e | ||
|
|
997d291d85 | ||
|
|
5f2660e1f5 | ||
|
|
451e4cf3b0 | ||
|
|
132b439359 | ||
|
|
04ce9050b6 | ||
|
|
27f8ee6b97 | ||
|
|
1c001ecd7a | ||
|
|
a961984f73 | ||
|
|
2d53799372 | ||
|
|
7275490322 | ||
|
|
f6a7cda7b6 | ||
|
|
d88b74064d | ||
|
|
b9f6b579f1 | ||
|
|
72ad5a142b | ||
|
|
d07f9dfbb2 | ||
|
|
33250ea678 | ||
|
|
300657162b | ||
|
|
7fcc76fa06 | ||
|
|
85fbaaf37a | ||
|
|
da97846483 | ||
|
|
7aa29a0dbb | ||
|
|
516d9f0eae | ||
|
|
bb5789b6ee | ||
|
|
f206bc51ff | ||
|
|
ecc82a3c27 | ||
|
|
6746be5a09 | ||
|
|
007d884a85 | ||
|
|
998416c54b | ||
|
|
873c515ee3 | ||
|
|
ee295c175b | ||
|
|
25ed0aa9bb | ||
|
|
4b4614ffb1 | ||
|
|
21adda8777 | ||
|
|
8ff0f4a616 | ||
|
|
08946da2db | ||
|
|
90b8a42349 | ||
|
|
3c92cd607b | ||
|
|
4f3008bfd8 | ||
|
|
dd1fa7c502 | ||
|
|
50556b8acb | ||
|
|
9da0541020 | ||
|
|
ab74be7abe | ||
|
|
b5c45a4d46 | ||
|
|
225e98dcee | ||
|
|
d66b227e07 | ||
|
|
ce67428c56 | ||
|
|
054e82b4b3 | ||
|
|
7d4a9db191 | ||
|
|
39f97bb4e8 | ||
|
|
8f81157432 | ||
|
|
5141570f24 | ||
|
|
f86d512672 | ||
|
|
ab341359f5 | ||
|
|
f98da26b38 | ||
|
|
d0cd624d2b | ||
|
|
c8c4bd099e | ||
|
|
36c14cf214 | ||
|
|
a7c9cf3a6b | ||
|
|
9aee394dc6 | ||
|
|
05eb9d155f | ||
|
|
0669fe8f02 | ||
|
|
cabb97f9a9 | ||
|
|
41b1db4dc6 | ||
|
|
8bc76b3684 | ||
|
|
245b753904 | ||
|
|
86a6c21e79 | ||
|
|
8cc0379da1 | ||
|
|
e56bfadc58 | ||
|
|
583e80708b | ||
|
|
5cf4d8a1ec | ||
|
|
ef3c6ac276 | ||
|
|
4129436f7e | ||
|
|
0808a04ee8 | ||
|
|
c99977b67c | ||
|
|
8d3d3fdd4a | ||
|
|
c4973908e4 | ||
|
|
3bb43d5f03 | ||
|
|
209d454b5f | ||
|
|
b385fe0586 | ||
|
|
487c4b6725 | ||
|
|
667846cba1 | ||
|
|
ccbb261c35 | ||
|
|
f35fd2a6b0 | ||
|
|
5682a5ef36 | ||
|
|
b66af09b75 | ||
|
|
9b5841f17c | ||
|
|
103de7acdc | ||
|
|
c2b39f4a5f | ||
|
|
2bd198d180 | ||
|
|
5b2fee13cd | ||
|
|
6ceedabb27 | ||
|
|
dac71d688a | ||
|
|
dc304fb3af | ||
|
|
6ae56b61cf | ||
|
|
6698be57c8 | ||
|
|
ef9dbff112 | ||
|
|
561f8ff513 | ||
|
|
945d2e697c | ||
|
|
94c4f32df0 | ||
|
|
ab62202eb9 | ||
|
|
063c23deff | ||
|
|
3868307efd | ||
|
|
e0c834285f | ||
|
|
e99b4e85b9 | ||
|
|
20ab122f80 | ||
|
|
98dd235819 |
140
.gitlab-ci.yml
140
.gitlab-ci.yml
@@ -1,9 +1,9 @@
|
||||
stages:
|
||||
- build
|
||||
- assign_test
|
||||
- host_test
|
||||
- unit_test
|
||||
- test
|
||||
- test_report
|
||||
- integration_test
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
@@ -133,6 +133,8 @@ build_ssc_01:
|
||||
build_ssc_02:
|
||||
<<: *build_ssc_template
|
||||
|
||||
# If you want to add new build ssc jobs, please add it into dependencies of `assign_test` and `.test_template`
|
||||
|
||||
build_esp_idf_tests:
|
||||
<<: *build_template
|
||||
artifacts:
|
||||
@@ -140,7 +142,7 @@ build_esp_idf_tests:
|
||||
- tools/unit-test-app/output
|
||||
- components/idf_test/unit_test/TestCaseAll.yml
|
||||
- components/idf_test/unit_test/CIConfigs/*.yml
|
||||
expire_in: 6 mos
|
||||
expire_in: 1 mos
|
||||
script:
|
||||
- cd tools/unit-test-app
|
||||
- make help # make sure kconfig tools are built in single process
|
||||
@@ -199,6 +201,7 @@ build_examples_06:
|
||||
build_examples_07:
|
||||
<<: *build_examples_template
|
||||
|
||||
# If you want to add new build example jobs, please add it into dependencies of `.example_test_template`
|
||||
|
||||
build_docs:
|
||||
stage: build
|
||||
@@ -222,54 +225,44 @@ build_docs:
|
||||
- make html
|
||||
- ./check_doc_warnings.sh
|
||||
|
||||
test_nvs_on_host:
|
||||
stage: test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
.host_test_template: &host_test_template
|
||||
stage: host_test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
|
||||
tags:
|
||||
- nvs_host_test
|
||||
- host_test
|
||||
dependencies: []
|
||||
|
||||
test_nvs_on_host:
|
||||
<<: *host_test_template
|
||||
script:
|
||||
- cd components/nvs_flash/test_nvs_host
|
||||
- make test
|
||||
|
||||
test_partition_table_on_host:
|
||||
stage: test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
<<: *host_test_template
|
||||
tags:
|
||||
- build
|
||||
dependencies: []
|
||||
script:
|
||||
- cd components/partition_table/test_gen_esp32part_host
|
||||
- ./gen_esp32part_tests.py
|
||||
|
||||
test_wl_on_host:
|
||||
stage: test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
tags:
|
||||
- wl_host_test
|
||||
<<: *host_test_template
|
||||
artifacts:
|
||||
paths:
|
||||
- components/wear_levelling/test_wl_host/coverage_report.zip
|
||||
dependencies: []
|
||||
script:
|
||||
- cd components/wear_levelling/test_wl_host
|
||||
- make test
|
||||
|
||||
test_multi_heap_on_host:
|
||||
stage: test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
tags:
|
||||
- wl_host_test
|
||||
<<: *host_test_template
|
||||
script:
|
||||
- cd components/heap/test_multi_heap_host
|
||||
- ./test_all_configs.sh
|
||||
|
||||
test_build_system:
|
||||
stage: test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
tags:
|
||||
- build_test
|
||||
dependencies: []
|
||||
<<: *host_test_template
|
||||
script:
|
||||
- ${IDF_PATH}/tools/ci/test_configure_ci_environment.sh
|
||||
- rm -rf test_build_system
|
||||
@@ -277,61 +270,7 @@ test_build_system:
|
||||
- cd test_build_system
|
||||
- ${IDF_PATH}/tools/ci/test_build_system.sh
|
||||
|
||||
test_report:
|
||||
stage: test_report
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
tags:
|
||||
- report
|
||||
only:
|
||||
- master
|
||||
- triggers
|
||||
- /^release\/v/
|
||||
- /^v\d+\.\d+(\.\d+)?($|-)/
|
||||
variables:
|
||||
LOG_PATH: "$CI_PROJECT_DIR/$CI_COMMIT_SHA"
|
||||
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test"
|
||||
REPORT_PATH: "$CI_PROJECT_DIR/CI_Test_Report"
|
||||
MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/tools/unit-test-app/tools/ModuleDefinition.yml"
|
||||
#dependencies:
|
||||
#We need all UT* and IT* artifacts except for only a few other
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- $REPORT_PATH
|
||||
- $LOG_PATH
|
||||
expire_in: 12 mos
|
||||
script:
|
||||
# calc log path
|
||||
- VER_NUM=`git rev-list HEAD | wc -l | awk '{print $1}'`
|
||||
- SHA_ID=`echo $CI_COMMIT_SHA | cut -c 1-7`
|
||||
- REVISION="${VER_NUM}_${SHA_ID}"
|
||||
# replace / to _ in branch name
|
||||
- ESCAPED_BRANCH_NAME=`echo $CI_COMMIT_REF_NAME | sed 's/\//___/g'`
|
||||
# result path and artifacts path
|
||||
- RESULT_PATH="$CI_PROJECT_NAME/$ESCAPED_BRANCH_NAME/$REVISION"
|
||||
- ARTIFACTS_PATH="$GITLAB_HTTP_SERVER/idf/esp-idf/builds/$CI_JOB_ID/artifacts/browse/$CI_COMMIT_SHA"
|
||||
# clone test bench
|
||||
- git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git
|
||||
- cd auto_test_script
|
||||
- python $CHECKOUT_REF_SCRIPT auto_test_script
|
||||
# generate report
|
||||
- TEST_RESULT=Pass
|
||||
- python CITestReport.py -l $LOG_PATH -t $TEST_CASE_FILE_PATH -p $REPORT_PATH -r $RESULT_PATH -a $ARTIFACTS_PATH -m $MODULE_UPDATE_FILE || TEST_RESULT=Fail
|
||||
# commit to CI-test-result project
|
||||
- git clone $GITLAB_SSH_SERVER/qa/CI-test-result.git
|
||||
- rm -rf "CI-test-result/RawData/$RESULT_PATH"
|
||||
- cp -R $CI_PROJECT_NAME CI-test-result/RawData
|
||||
- cd CI-test-result
|
||||
# config git user
|
||||
- git config --global user.email "ci-test-result@espressif.com"
|
||||
- git config --global user.name "ci-test-result"
|
||||
# commit test result
|
||||
- git add .
|
||||
- git commit . -m "update test result for $CI_PROJECT_NAME/$CI_COMMIT_REF_NAME/$CI_COMMIT_SHA, pipeline ID $CI_PIPELINE_ID" || exit 0
|
||||
- git push origin master
|
||||
- test "${TEST_RESULT}" = "Pass" || exit 1
|
||||
|
||||
push_master_to_github:
|
||||
push_to_github:
|
||||
stage: deploy
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
tags:
|
||||
@@ -342,8 +281,6 @@ push_master_to_github:
|
||||
- /^v\d+\.\d+(\.\d+)?($|-)/
|
||||
when: on_success
|
||||
dependencies: []
|
||||
variables:
|
||||
GITHUB_PUSH_REFS: refs/remotes/origin/release refs/remotes/origin/master
|
||||
before_script: *do_nothing_before
|
||||
script:
|
||||
- mkdir -p ~/.ssh
|
||||
@@ -354,16 +291,13 @@ push_master_to_github:
|
||||
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||
- git remote remove github &>/dev/null || true
|
||||
- git remote add github git@github.com:espressif/esp-idf.git
|
||||
# What the next line of script does: goes through the list of refs for all branches we push to github,
|
||||
# generates a snippet of shell which is evaluated. The snippet checks CI_COMMIT_SHA against the SHA
|
||||
# (aka objectname) at tip of each branch, and if any SHAs match then it checks out the local branch
|
||||
# and then pushes that ref to a corresponding github branch
|
||||
- eval $(git for-each-ref --shell bash --format 'if [ $CI_COMMIT_SHA == %(objectname) ]; then git checkout -B %(refname:strip=3); git push --follow-tags github %(refname:strip=3); fi;' $GITHUB_PUSH_REFS)
|
||||
|
||||
# Need separate push commands for tag builds and for branch builds
|
||||
- "[ -n \"${CI_COMMIT_TAG}\" ] && git push github ${CI_COMMIT_TAG}"
|
||||
- "[ -z \"${CI_COMMIT_TAG}\" ] && git push github ${CI_COMMIT_SHA}:refs/heads/${CI_COMMIT_REF_NAME}"
|
||||
|
||||
deploy_docs:
|
||||
stage: deploy
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
stage: host_test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
|
||||
tags:
|
||||
- deploy
|
||||
only:
|
||||
@@ -389,8 +323,8 @@ deploy_docs:
|
||||
- ssh $DOCS_SERVER -x "cd $DOCS_PATH && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest"
|
||||
|
||||
check_doc_links:
|
||||
stage: test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
stage: host_test
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
|
||||
tags:
|
||||
- check_doc_links
|
||||
only:
|
||||
@@ -478,21 +412,28 @@ assign_test:
|
||||
- python CIAssignTestCases.py -t $IDF_PATH/components/idf_test/integration_test -c $IDF_PATH/.gitlab-ci.yml -b $IDF_PATH/SSC/ssc_bin
|
||||
|
||||
.example_test_template: &example_test_template
|
||||
stage: test
|
||||
stage: integration_test
|
||||
when: on_success
|
||||
only:
|
||||
- master
|
||||
- /^release\/v/
|
||||
- /^v\d+\.\d+(\.\d+)?($|-)/
|
||||
- triggers
|
||||
# gitlab ci do not support match job with RegEx or wildcard now in dependencies.
|
||||
# we have a lot build example jobs and the binaries them exceed the limitation of artifacts.
|
||||
# we can't artifact them in one job. For example test jobs, download all artifacts from previous stages.
|
||||
dependencies:
|
||||
- assign_test
|
||||
- build_examples_00
|
||||
- build_examples_01
|
||||
- build_examples_02
|
||||
- build_examples_03
|
||||
- build_examples_04
|
||||
- build_examples_05
|
||||
- build_examples_06
|
||||
- build_examples_07
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- $LOG_PATH
|
||||
expire_in: 6 mos
|
||||
expire_in: 1 mos
|
||||
variables:
|
||||
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
|
||||
TEST_CASE_PATH: "$CI_PROJECT_DIR/examples"
|
||||
@@ -506,14 +447,13 @@ assign_test:
|
||||
- python Runner.py $TEST_CASE_PATH -c $CONFIG_FILE
|
||||
|
||||
.test_template: &test_template
|
||||
stage: test
|
||||
stage: integration_test
|
||||
when: on_success
|
||||
only:
|
||||
- master
|
||||
- /^release\/v/
|
||||
- /^v\d+\.\d+(\.\d+)?($|-)/
|
||||
- triggers
|
||||
allow_failure: true
|
||||
dependencies:
|
||||
- assign_test
|
||||
- build_ssc_00
|
||||
@@ -523,7 +463,7 @@ assign_test:
|
||||
when: always
|
||||
paths:
|
||||
- $LOG_PATH
|
||||
expire_in: 6 mos
|
||||
expire_in: 1 mos
|
||||
variables:
|
||||
LOCAL_ENV_CONFIG_PATH: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/ESP32_IDF"
|
||||
LOG_PATH: "$CI_PROJECT_DIR/$CI_COMMIT_SHA"
|
||||
@@ -564,7 +504,7 @@ nvs_compatible_test:
|
||||
paths:
|
||||
- $LOG_PATH
|
||||
- nvs_wifi.bin
|
||||
expire_in: 6 mos
|
||||
expire_in: 1 mos
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- NVS_Compatible
|
||||
|
||||
31
README.md
31
README.md
@@ -4,22 +4,27 @@
|
||||
|
||||
ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip.
|
||||
|
||||
# Developing With the ESP-IDF
|
||||
# Developing With ESP-IDF
|
||||
|
||||
## Setting Up ESP-IDF
|
||||
|
||||
See setup guides for detailed instructions to set up the ESP-IDF:
|
||||
|
||||
* [Windows Setup Guide](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html)
|
||||
* [Mac OS Setup Guide](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html)
|
||||
* [Linux Setup Guide](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
|
||||
* [Getting Started Guide for the stable ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/)
|
||||
* [Getting Started Guide for the latest (master branch) ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/)
|
||||
|
||||
## Finding a Project
|
||||
|
||||
As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, ESP-IDF comes with some example projects in the [examples](examples) directory.
|
||||
As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in Getting Started, ESP-IDF comes with some example projects in the [examples](examples) directory.
|
||||
|
||||
Once you've found the project you want to work with, change to its directory and you can configure and build it.
|
||||
|
||||
To start your own project based on an example, copy the example project directory outside of the ESP-IDF directory.
|
||||
|
||||
# Quick Reference
|
||||
|
||||
See the Getting Started guide links above for a detailed setup guide. This is a quick reference for common commands when working with ESP-IDF projects:
|
||||
|
||||
## Configuring the Project
|
||||
|
||||
`make menuconfig`
|
||||
@@ -36,15 +41,17 @@ Once done configuring, press Escape multiple times to exit and say "Yes" to save
|
||||
|
||||
## Compiling the Project
|
||||
|
||||
`make all`
|
||||
`make -j4 all`
|
||||
|
||||
... will compile app, bootloader and generate a partition table based on the config.
|
||||
|
||||
NOTE: The `-j4` option causes `make` to run 4 parallel jobs. This is much faster than the default single job. The recommended number to pass to this option is `-j(number of CPUs + 1)`.
|
||||
|
||||
## Flashing the Project
|
||||
|
||||
When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running:
|
||||
|
||||
`make flash`
|
||||
`make -j4 flash`
|
||||
|
||||
This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `make menuconfig`.
|
||||
|
||||
@@ -56,24 +63,24 @@ The `make monitor` target uses the [idf_monitor tool](https://esp-idf.readthedoc
|
||||
|
||||
Exit the monitor by typing Ctrl-].
|
||||
|
||||
To flash and monitor output in one pass, you can run:
|
||||
To build, flash and monitor output in one pass, you can run:
|
||||
|
||||
`make flash monitor`
|
||||
`make -j4 flash monitor`
|
||||
|
||||
## Compiling & Flashing Just the App
|
||||
## Compiling & Flashing Only the App
|
||||
|
||||
After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table:
|
||||
|
||||
* `make app` - build just the app.
|
||||
* `make app-flash` - flash just the app.
|
||||
|
||||
`make app-flash` will automatically rebuild the app if it needs it.
|
||||
`make app-flash` will automatically rebuild the app if any source files have changed.
|
||||
|
||||
(In normal development there's no downside to reflashing the bootloader and partition table each time, if they haven't changed.)
|
||||
|
||||
## Parallel Builds
|
||||
|
||||
ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to or one more than the number of CPU cores in your system.)
|
||||
ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to the number of CPU cores in your system, plus one.)
|
||||
|
||||
Multiple make functions can be combined into one. For example: to build the app & bootloader using 5 jobs in parallel, then flash everything, and then display serial output from the ESP32 run:
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#define CMD_WRDI 0x04
|
||||
#define CMD_RDSR 0x05
|
||||
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
|
||||
#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */
|
||||
|
||||
static const char *TAG = "qio_mode";
|
||||
|
||||
@@ -65,6 +66,11 @@ static void write_status_8b_wrsr2(unsigned new_status);
|
||||
/* Write 16 bit status using WRSR */
|
||||
static void write_status_16b_wrsr(unsigned new_status);
|
||||
|
||||
/* Read 8 bit status of XM25QU64A */
|
||||
static unsigned read_status_8b_xmc25qu64a();
|
||||
/* Write 8 bit status of XM25QU64A */
|
||||
static void write_status_8b_xmc25qu64a(unsigned new_status);
|
||||
|
||||
#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */
|
||||
|
||||
#ifndef CONFIG_BOOTLOADER_SPI_WP_PIN // Set in menuconfig if SPI flasher config is set to a quad mode
|
||||
@@ -84,11 +90,12 @@ static void write_status_16b_wrsr(unsigned new_status);
|
||||
Searching of this table stops when the first match is found.
|
||||
*/
|
||||
const static qio_info_t chip_data[] = {
|
||||
/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */
|
||||
{ "MXIC", 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 },
|
||||
{ "ISSI", 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */
|
||||
{ "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
|
||||
{ "GD", 0xC8, 0x6000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
|
||||
/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */
|
||||
{ "MXIC", 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 },
|
||||
{ "ISSI", 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */
|
||||
{ "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
|
||||
{ "GD", 0xC8, 0x6000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
|
||||
{ "XM25QU64A", 0x20, 0x3817, 0xFFFF, read_status_8b_xmc25qu64a, write_status_8b_xmc25qu64a, 6 },
|
||||
|
||||
/* Final entry is default entry, if no other IDs have matched.
|
||||
|
||||
@@ -96,7 +103,7 @@ const static qio_info_t chip_data[] = {
|
||||
GigaDevice (mfg ID 0xC8, flash IDs including 4016),
|
||||
FM25Q32 (QOUT mode only, mfg ID 0xA1, flash IDs including 4016)
|
||||
*/
|
||||
{ NULL, 0xFF, 0xFFFF, 0xFFFF, read_status_8b_rdsr2, write_status_8b_wrsr2, 1 },
|
||||
{ NULL, 0xFF, 0xFFFF, 0xFFFF, read_status_8b_rdsr2, write_status_8b_wrsr2, 1 },
|
||||
};
|
||||
|
||||
#define NUM_CHIPS (sizeof(chip_data) / sizeof(qio_info_t))
|
||||
@@ -252,6 +259,24 @@ static void write_status_16b_wrsr(unsigned new_status)
|
||||
execute_flash_command(CMD_WRSR, new_status, 16, 0);
|
||||
}
|
||||
|
||||
static unsigned read_status_8b_xmc25qu64a()
|
||||
{
|
||||
execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
uint32_t read_status = execute_flash_command(CMD_RDSR, 0, 0, 8);
|
||||
execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
|
||||
return read_status;
|
||||
}
|
||||
|
||||
static void write_status_8b_xmc25qu64a(unsigned new_status)
|
||||
{
|
||||
execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
execute_flash_command(CMD_WRSR, new_status, 8, 0);
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
|
||||
}
|
||||
|
||||
static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
|
||||
{
|
||||
SPIFLASH.user2.usr_command_value = command;
|
||||
|
||||
@@ -156,6 +156,38 @@ config BT_ACL_CONNECTIONS
|
||||
help
|
||||
Maximum BT/BLE connection count
|
||||
|
||||
config BLE_SCAN_DUPLICATE
|
||||
bool "BLE Scan Duplicate Options "
|
||||
depends on BLUEDROID_ENABLED
|
||||
default y
|
||||
help
|
||||
This select enables parameters setting of BLE scan duplicate.
|
||||
|
||||
config DUPLICATE_SCAN_CACHE_SIZE
|
||||
int "Maximum number of devices in scan duplicate filter"
|
||||
depends on BLE_SCAN_DUPLICATE
|
||||
range 10 1000
|
||||
default 500
|
||||
help
|
||||
Maximum number of devices which can be recorded in scan duplicate filter.
|
||||
When the maximum amount of device in the filter is reached, the cache will be refreshed.
|
||||
|
||||
config BLE_MESH_SCAN_DUPLICATE_EN
|
||||
bool "Special duplicate scan mechanism for BLE Mesh scan"
|
||||
depends on BLE_SCAN_DUPLICATE
|
||||
default n
|
||||
help
|
||||
This enables the BLE scan duplicate for special BLE Mesh scan.
|
||||
|
||||
config MESH_DUPLICATE_SCAN_CACHE_SIZE
|
||||
int "Maximum number of Mesh adv packets in scan duplicate filter"
|
||||
depends on BLE_MESH_SCAN_DUPLICATE_EN
|
||||
range 10 200
|
||||
default 50
|
||||
help
|
||||
Maximum number of adv packets which can be recorded in duplicate scan cache for BLE Mesh.
|
||||
When the maximum amount of device in the filter is reached, the cache will be refreshed.
|
||||
|
||||
config SMP_ENABLE
|
||||
bool
|
||||
depends on BLUEDROID_ENABLED
|
||||
|
||||
@@ -264,6 +264,13 @@ typedef enum {
|
||||
3. directed advertising packets addressed to this device.*/
|
||||
} esp_ble_scan_filter_t;
|
||||
|
||||
/// Ble scan duplicate type
|
||||
typedef enum {
|
||||
BLE_SCAN_DUPLICATE_DISABLE = 0x0, /*!< the Link Layer should generate advertising reports to the host for each packet received */
|
||||
BLE_SCAN_DUPLICATE_ENABLE = 0x1, /*!< the Link Layer should filter out duplicate advertising reports to the Host */
|
||||
BLE_SCAN_DUPLICATE_MAX = 0x2, /*!< 0x02 – 0xFF, Reserved for future use */
|
||||
} esp_ble_scan_duplicate_t;
|
||||
|
||||
/// Ble scan parameters
|
||||
typedef struct {
|
||||
esp_ble_scan_type_t scan_type; /*!< Scan type */
|
||||
@@ -279,6 +286,9 @@ typedef struct {
|
||||
Range: 0x0004 to 0x4000 Default: 0x0010 (10 ms)
|
||||
Time = N * 0.625 msec
|
||||
Time Range: 2.5 msec to 10240 msec */
|
||||
esp_ble_scan_duplicate_t scan_duplicate; /*!< The Scan_Duplicates parameter controls whether the Link Layer should filter out
|
||||
duplicate advertising reports (BLE_SCAN_DUPLICATE_ENABLE) to the Host, or if the Link Layer should generate
|
||||
advertising reports for each packet received */
|
||||
} esp_ble_scan_params_t;
|
||||
|
||||
/// Connection update parameters
|
||||
|
||||
@@ -4568,6 +4568,7 @@ void bta_dm_ble_set_scan_fil_params(tBTA_DM_MSG *p_data)
|
||||
p_data->ble_set_scan_fil_params.scan_window,
|
||||
p_data->ble_set_scan_fil_params.scan_mode,
|
||||
p_data->ble_set_scan_fil_params.addr_type_own,
|
||||
p_data->ble_set_scan_fil_params.scan_duplicate_filter,
|
||||
p_data->ble_set_scan_fil_params.scan_filter_policy,
|
||||
p_data->ble_set_scan_fil_params.scan_param_setup_cback);
|
||||
}
|
||||
|
||||
@@ -968,6 +968,7 @@ void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
** scan_interval - scan interval
|
||||
** scan_window - scan window
|
||||
** scan_mode - scan mode
|
||||
** scan_duplicate_filter - scan duplicate filter
|
||||
** scan_param_setup_status_cback - Set scan param status callback
|
||||
**
|
||||
** Returns void
|
||||
@@ -975,7 +976,7 @@ void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
*******************************************************************************/
|
||||
void BTA_DmSetBleScanFilterParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
UINT32 scan_window, tBLE_SCAN_MODE scan_mode, UINT8 scan_fil_poilcy,
|
||||
UINT8 addr_type_own, tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback)
|
||||
UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback)
|
||||
{
|
||||
tBTA_DM_API_BLE_SCAN_FILTER_PARAMS *p_msg;
|
||||
|
||||
@@ -987,6 +988,7 @@ void BTA_DmSetBleScanFilterParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
p_msg->scan_window = scan_window;
|
||||
p_msg->scan_mode = scan_mode;
|
||||
p_msg->addr_type_own = addr_type_own;
|
||||
p_msg->scan_duplicate_filter = scan_duplicate_filter;
|
||||
p_msg->scan_filter_policy = scan_fil_poilcy;
|
||||
p_msg->scan_param_setup_cback = scan_param_setup_cback;
|
||||
|
||||
|
||||
@@ -485,6 +485,7 @@ typedef struct {
|
||||
UINT32 scan_window;
|
||||
tBLE_SCAN_MODE scan_mode;
|
||||
UINT8 addr_type_own;
|
||||
UINT8 scan_duplicate_filter;
|
||||
UINT8 scan_filter_policy;
|
||||
tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback;
|
||||
} tBTA_DM_API_BLE_SCAN_FILTER_PARAMS;
|
||||
|
||||
@@ -702,6 +702,10 @@ void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
|
||||
APPL_TRACE_ERROR("%s, malloc failed", __func__);
|
||||
}
|
||||
(*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
|
||||
if (cb_data.req_data.value != NULL) {
|
||||
osi_free(cb_data.req_data.value);
|
||||
cb_data.req_data.value = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
APPL_TRACE_ERROR("Not an registered servce attribute ID: 0x%04x",
|
||||
|
||||
@@ -1902,6 +1902,7 @@ extern void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
** scan_interval - scan interval
|
||||
** scan_window - scan window
|
||||
** scan_mode - scan mode
|
||||
** scan_duplicate_filter - scan duplicate filter
|
||||
** scan_param_setup_status_cback - Set scan param status callback
|
||||
**
|
||||
** Returns void
|
||||
@@ -1909,7 +1910,7 @@ extern void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
*******************************************************************************/
|
||||
extern void BTA_DmSetBleScanFilterParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
UINT32 scan_window, tBLE_SCAN_MODE scan_mode, UINT8 scan_fil_poilcy,
|
||||
UINT8 addr_type_own, tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback);
|
||||
UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
@@ -175,6 +175,10 @@ static void btc_dm_remove_ble_bonding_keys(void)
|
||||
|
||||
static void btc_dm_save_ble_bonding_keys(void)
|
||||
{
|
||||
if(!(pairing_cb.ble.is_penc_key_rcvd || pairing_cb.ble.is_pid_key_rcvd || pairing_cb.ble.is_pcsrk_key_rcvd ||
|
||||
pairing_cb.ble.is_lenc_key_rcvd || pairing_cb.ble.is_lcsrk_key_rcvd || pairing_cb.ble.is_lidk_key_rcvd)) {
|
||||
return ;
|
||||
}
|
||||
bt_bdaddr_t bd_addr;
|
||||
|
||||
bdcpy(bd_addr.address, pairing_cb.bd_addr);
|
||||
|
||||
@@ -41,7 +41,9 @@ static void btc_enable_bluetooth(void)
|
||||
|
||||
static void btc_disable_bluetooth(void)
|
||||
{
|
||||
#if (SMP_INCLUDED)
|
||||
btc_config_shut_down();
|
||||
#endif /* #if (SMP_INCLUDED) */
|
||||
if (BTA_DisableBluetooth() != BTA_SUCCESS) {
|
||||
future_ready(*btc_main_get_future_p(BTC_MAIN_DISABLE_FUTURE), FUTURE_FAIL);
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
blufi_env.frag_size = p_data->req_data.p_data->mtu - BLUFI_MTU_RESERVED_SIZE;
|
||||
break;
|
||||
case BTA_GATTS_CONF_EVT:
|
||||
LOG_DEBUG("CONIRM EVT\n");
|
||||
LOG_DEBUG("CONFIRM EVT\n");
|
||||
/* Nothing */
|
||||
break;
|
||||
case BTA_GATTS_CREATE_EVT:
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "bt_utils.h"
|
||||
#include "btc_common.h"
|
||||
#include "btc_manage.h"
|
||||
#include "alarm.h"
|
||||
|
||||
#if BTC_AV_INCLUDED
|
||||
|
||||
@@ -80,7 +81,7 @@ typedef struct {
|
||||
} btc_av_cb_t;
|
||||
|
||||
typedef struct {
|
||||
bt_bdaddr_t *target_bda;
|
||||
bt_bdaddr_t target_bda;
|
||||
uint16_t uuid;
|
||||
} btc_av_connect_req_t;
|
||||
|
||||
@@ -88,7 +89,8 @@ typedef struct {
|
||||
** Static variables
|
||||
******************************************************************************/
|
||||
static btc_av_cb_t btc_av_cb = {0};
|
||||
static TIMER_LIST_ENT tle_av_open_on_rc;
|
||||
|
||||
static osi_alarm_t *tle_av_open_on_rc = NULL;
|
||||
|
||||
/* both interface and media task needs to be ready to alloc incoming request */
|
||||
#define CHECK_BTAV_INIT() do \
|
||||
@@ -203,19 +205,18 @@ UNUSED_ATTR static const char *dump_av_sm_event_name(btc_av_sm_event_t event)
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void btc_initiate_av_open_tmr_hdlr(TIMER_LIST_ENT *tle)
|
||||
static void btc_initiate_av_open_tmr_hdlr(void *arg)
|
||||
{
|
||||
UNUSED(arg);
|
||||
BD_ADDR peer_addr;
|
||||
UNUSED(tle);
|
||||
btc_av_connect_req_t connect_req;
|
||||
UNUSED(tle);
|
||||
/* is there at least one RC connection - There should be */
|
||||
if (btc_rc_get_connected_peer(peer_addr)) {
|
||||
LOG_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
|
||||
/* In case of AVRCP connection request, we will initiate SRC connection */
|
||||
connect_req.target_bda = (bt_bdaddr_t *)&peer_addr;
|
||||
memcpy(connect_req.target_bda.address, peer_addr, sizeof(bt_bdaddr_t));
|
||||
connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
|
||||
btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_CONNECT_REQ_EVT, (char *)&connect_req);
|
||||
btc_dispatch_sm_event(BTC_AV_CONNECT_REQ_EVT, &connect_req, sizeof(btc_av_connect_req_t));
|
||||
} else {
|
||||
LOG_ERROR("%s No connected RC peers", __FUNCTION__);
|
||||
}
|
||||
@@ -289,7 +290,7 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data)
|
||||
case BTA_AV_PENDING_EVT:
|
||||
case BTC_AV_CONNECT_REQ_EVT: {
|
||||
if (event == BTC_AV_CONNECT_REQ_EVT) {
|
||||
memcpy(&btc_av_cb.peer_bda, ((btc_av_connect_req_t *)p_data)->target_bda,
|
||||
memcpy(&btc_av_cb.peer_bda, &((btc_av_connect_req_t *)p_data)->target_bda,
|
||||
sizeof(bt_bdaddr_t));
|
||||
BTA_AvOpen(btc_av_cb.peer_bda.address, btc_av_cb.bta_handle,
|
||||
TRUE, BTA_SEC_AUTHENTICATE, ((btc_av_connect_req_t *)p_data)->uuid);
|
||||
@@ -313,10 +314,8 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data)
|
||||
*/
|
||||
|
||||
LOG_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
|
||||
memset(&tle_av_open_on_rc, 0, sizeof(tle_av_open_on_rc));
|
||||
tle_av_open_on_rc.param = (UINT32)btc_initiate_av_open_tmr_hdlr;
|
||||
btu_start_timer(&tle_av_open_on_rc, BTU_TTYPE_USER_FUNC,
|
||||
BTC_TIMEOUT_AV_OPEN_ON_RC_SECS);
|
||||
tle_av_open_on_rc = osi_alarm_new("AVconn", btc_initiate_av_open_tmr_hdlr, NULL, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000);
|
||||
osi_alarm_set(tle_av_open_on_rc, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000);
|
||||
btc_rc_handler(event, p_data);
|
||||
break;
|
||||
|
||||
@@ -329,9 +328,9 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data)
|
||||
break;
|
||||
|
||||
case BTA_AV_RC_CLOSE_EVT:
|
||||
if (tle_av_open_on_rc.in_use) {
|
||||
LOG_DEBUG("BTA_AV_RC_CLOSE_EVT: Stopping AV timer.");
|
||||
btu_stop_timer(&tle_av_open_on_rc);
|
||||
if (tle_av_open_on_rc) {
|
||||
osi_alarm_free(tle_av_open_on_rc);
|
||||
tle_av_open_on_rc = NULL;
|
||||
}
|
||||
btc_rc_handler(event, p_data);
|
||||
break;
|
||||
@@ -616,7 +615,7 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
|
||||
break;
|
||||
|
||||
case BTC_AV_CONNECT_REQ_EVT:
|
||||
if (memcmp ((bt_bdaddr_t *)p_data, &(btc_av_cb.peer_bda),
|
||||
if (memcmp (&((btc_av_connect_req_t *)p_data)->target_bda, &(btc_av_cb.peer_bda),
|
||||
sizeof(btc_av_cb.peer_bda)) == 0) {
|
||||
LOG_DEBUG("%s: Ignore BTC_AVCONNECT_REQ_EVT for same device\n", __func__);
|
||||
} else {
|
||||
@@ -972,7 +971,7 @@ bt_status_t btc_a2d_sink_init(void)
|
||||
static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid)
|
||||
{
|
||||
btc_av_connect_req_t connect_req;
|
||||
connect_req.target_bda = bd_addr;
|
||||
memcpy(&connect_req.target_bda, bd_addr, sizeof(bt_bdaddr_t));
|
||||
connect_req.uuid = uuid;
|
||||
LOG_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
@@ -1001,7 +1000,6 @@ bt_status_t btc_a2d_sink_connect(bt_bdaddr_t *remote_bda)
|
||||
static void btc_a2d_sink_deinit(void)
|
||||
{
|
||||
LOG_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
btc_dm_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
|
||||
#if (BTA_AV_SINK_INCLUDED == TRUE)
|
||||
btc_dm_disable_service(BTA_A2DP_SINK_SERVICE_ID);
|
||||
@@ -1232,6 +1230,9 @@ void btc_a2dp_call_handler(btc_msg_t *msg)
|
||||
btc_a2dp_sink_reg_data_cb(arg->data_cb);
|
||||
break;
|
||||
}
|
||||
case BTC_AV_CONNECT_REQ_EVT:
|
||||
btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, (char *)msg->arg);
|
||||
break;
|
||||
default:
|
||||
LOG_WARN("%s : unhandled event: %d\n", __FUNCTION__, msg->act);
|
||||
}
|
||||
|
||||
@@ -641,7 +641,7 @@ static void btc_media_task_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
OI_STATUS status;
|
||||
int num_sbc_frames = p_msg->num_frames_to_be_processed;
|
||||
UINT32 sbc_frame_len = p_msg->len - 1;
|
||||
availPcmBytes = 2 * sizeof(pcmData);
|
||||
availPcmBytes = sizeof(pcmData);
|
||||
|
||||
if ((btc_media_cb.peer_sep == AVDT_TSEP_SNK) || (btc_media_cb.rx_flush)) {
|
||||
APPL_TRACE_DEBUG(" State Changed happened in this tick ");
|
||||
@@ -671,7 +671,7 @@ static void btc_media_task_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
p_msg->len = sbc_frame_len + 1;
|
||||
}
|
||||
|
||||
btc_a2d_data_cb_to_app((uint8_t *)pcmData, (2 * sizeof(pcmData) - availPcmBytes));
|
||||
btc_a2d_data_cb_to_app((uint8_t *)pcmData, (sizeof(pcmData) - availPcmBytes));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
@@ -520,9 +520,8 @@ static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params, tBT
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("API_Ble_AppStartAdvertising\n");
|
||||
|
||||
LOG_DEBUG("API_Ble_AppStartAdvertising\n");
|
||||
memcpy(peer_addr.bda, ble_adv_params->peer_addr, ESP_BD_ADDR_LEN);
|
||||
peer_addr.type = ble_adv_params->peer_addr_type;
|
||||
BTA_DmSetBleAdvParamsAll(ble_adv_params->adv_int_min,
|
||||
@@ -561,6 +560,7 @@ static void btc_ble_set_scan_params(esp_ble_scan_params_t *scan_params, tBLE_SCA
|
||||
BLE_ISVALID_PARAM(scan_params->scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX) &&
|
||||
BLE_ISVALID_PARAM(scan_params->own_addr_type, BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_RPA_RANDOM) &&
|
||||
BLE_ISVALID_PARAM(scan_params->scan_filter_policy, BLE_SCAN_FILTER_ALLOW_ALL, BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR) &&
|
||||
BLE_ISVALID_PARAM(scan_params->scan_duplicate, BLE_SCAN_DUPLICATE_DISABLE, BLE_SCAN_DUPLICATE_MAX -1) &&
|
||||
(scan_params->scan_type == BTM_BLE_SCAN_MODE_ACTI || scan_params->scan_type == BTM_BLE_SCAN_MODE_PASS)) {
|
||||
BTA_DmSetBleScanFilterParams(ESP_DEFAULT_GATT_IF, /*client_if*/
|
||||
scan_params->scan_interval,
|
||||
@@ -568,6 +568,7 @@ static void btc_ble_set_scan_params(esp_ble_scan_params_t *scan_params, tBLE_SCA
|
||||
scan_params->scan_type,
|
||||
scan_params->scan_filter_policy,
|
||||
scan_params->own_addr_type,
|
||||
scan_params->scan_duplicate,
|
||||
scan_param_setup_cback);
|
||||
} else {
|
||||
btc_scan_params_callback(ESP_DEFAULT_GATT_IF, BTM_ILLEGAL_VALUE);
|
||||
@@ -723,12 +724,12 @@ static void btc_add_whitelist_complete_callback(UINT8 status, tBTM_WL_OPERATION
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_set_rand_addr_callback(UINT8 status)
|
||||
static void btc_set_rand_addr_callback(UINT8 status)
|
||||
{
|
||||
esp_ble_gap_cb_param_t param;
|
||||
bt_status_t ret;
|
||||
btc_msg_t msg;
|
||||
param.set_rand_addr_cmpl.status = btc_btm_status_to_esp_status(status); //todo status
|
||||
param.set_rand_addr_cmpl.status = btc_btm_status_to_esp_status(status); //todo status
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_GAP_BLE;
|
||||
msg.act = ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT;
|
||||
@@ -1010,6 +1011,13 @@ void btc_gap_ble_arg_deep_free(btc_msg_t *msg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_GAP_BLE_SET_SECURITY_PARAM_EVT: {
|
||||
uint8_t *value = ((btc_ble_gap_args_t *)msg->arg)->set_security_param.value;
|
||||
if (value) {
|
||||
osi_free(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_DEBUG("Unhandled deep free %d\n", msg->act);
|
||||
break;
|
||||
@@ -1108,36 +1116,37 @@ void btc_gap_ble_call_handler(btc_msg_t *msg)
|
||||
break;
|
||||
}
|
||||
case BTC_GAP_BLE_SET_SECURITY_PARAM_EVT: {
|
||||
uint8_t *value = arg->set_security_param.value;
|
||||
switch(arg->set_security_param.param_type) {
|
||||
case ESP_BLE_SM_PASSKEY:
|
||||
break;
|
||||
case ESP_BLE_SM_AUTHEN_REQ_MODE: {
|
||||
uint8_t authen_req = 0;
|
||||
STREAM_TO_UINT8(authen_req, arg->set_security_param.value);
|
||||
STREAM_TO_UINT8(authen_req, value);
|
||||
bta_dm_co_ble_set_auth_req(authen_req);
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_SM_IOCAP_MODE: {
|
||||
uint8_t iocap = 0;
|
||||
STREAM_TO_UINT8(iocap, arg->set_security_param.value);
|
||||
STREAM_TO_UINT8(iocap, value);
|
||||
bta_dm_co_ble_set_io_cap(iocap);
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_SM_SET_INIT_KEY: {
|
||||
uint8_t init_key = 0;
|
||||
STREAM_TO_UINT8(init_key, arg->set_security_param.value);
|
||||
STREAM_TO_UINT8(init_key, value);
|
||||
bta_dm_co_ble_set_init_key_req(init_key);
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_SM_SET_RSP_KEY: {
|
||||
uint8_t rsp_key = 0;
|
||||
STREAM_TO_UINT8(rsp_key, arg->set_security_param.value);
|
||||
STREAM_TO_UINT8(rsp_key, value);
|
||||
bta_dm_co_ble_set_rsp_key_req(rsp_key);
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_SM_MAX_KEY_SIZE: {
|
||||
uint8_t key_size = 0;
|
||||
STREAM_TO_UINT8(key_size, arg->set_security_param.value);
|
||||
STREAM_TO_UINT8(key_size, value);
|
||||
bta_dm_co_ble_set_max_key_size(key_size);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -671,7 +671,7 @@ void btc_gattc_call_handler(btc_msg_t *msg)
|
||||
btc_ble_gattc_args_t *arg = (btc_ble_gattc_args_t *)(msg->arg);
|
||||
switch (msg->act) {
|
||||
case BTC_GATTC_ACT_APP_REGISTER:
|
||||
LOG_ERROR("%s()", __func__);
|
||||
LOG_DEBUG("%s()", __func__);
|
||||
btc_gattc_app_register(arg);
|
||||
break;
|
||||
case BTC_GATTC_ACT_APP_UNREGISTER:
|
||||
|
||||
@@ -506,6 +506,8 @@ static void btc_gatts_cb_param_copy_req(btc_msg_t *msg, void *p_dest, void *p_sr
|
||||
if (p_dest_data->req_data.p_data != NULL) {
|
||||
memcpy(p_dest_data->req_data.p_data, p_src_data->req_data.p_data,
|
||||
sizeof(tBTA_GATTS_REQ_DATA));
|
||||
} else {
|
||||
LOG_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -528,9 +530,6 @@ static void btc_gatts_cb_param_copy_free(btc_msg_t *msg, tBTA_GATTS *p_data)
|
||||
}
|
||||
break;
|
||||
case BTA_GATTS_CONF_EVT:
|
||||
if (p_data && p_data->req_data.value){
|
||||
osi_free(p_data->req_data.value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -759,6 +758,9 @@ void btc_gatts_cb_handler(btc_msg_t *msg)
|
||||
param.write.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
|
||||
param.write.trans_id = p_data->req_data.trans_id;
|
||||
memcpy(param.write.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN);
|
||||
if (p_data->req_data.p_data == NULL) {
|
||||
break;
|
||||
}
|
||||
param.write.handle = p_data->req_data.p_data->write_req.handle;
|
||||
param.write.offset = p_data->req_data.p_data->write_req.offset;
|
||||
param.write.need_rsp = p_data->req_data.p_data->write_req.need_rsp;
|
||||
@@ -775,6 +777,9 @@ void btc_gatts_cb_handler(btc_msg_t *msg)
|
||||
param.exec_write.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
|
||||
param.exec_write.trans_id = p_data->req_data.trans_id;
|
||||
memcpy(param.exec_write.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN);
|
||||
if (p_data->req_data.p_data == NULL) {
|
||||
break;
|
||||
}
|
||||
param.exec_write.exec_write_flag = p_data->req_data.p_data->exec_write;
|
||||
|
||||
btc_gatts_cb_to_app(ESP_GATTS_EXEC_WRITE_EVT, gatts_if, ¶m);
|
||||
|
||||
@@ -92,6 +92,7 @@ static void hci_hal_env_init(
|
||||
static void hci_hal_env_deinit(void)
|
||||
{
|
||||
fixed_queue_free(hci_hal_env.rx_q, hci_hal_env.allocator->free);
|
||||
hci_hal_env.rx_q = NULL;
|
||||
}
|
||||
|
||||
static bool hal_open(const hci_hal_callbacks_t *upper_callbacks)
|
||||
@@ -260,6 +261,10 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len)
|
||||
BT_HDR *pkt;
|
||||
size_t pkt_size;
|
||||
|
||||
if (hci_hal_env.rx_q == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pkt_size = BT_HDR_SIZE + len;
|
||||
pkt = (BT_HDR *)hci_hal_env.allocator->alloc(pkt_size);
|
||||
if (!pkt) {
|
||||
|
||||
@@ -412,6 +412,7 @@ void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
|
||||
{
|
||||
tAVDT_TC_TBL *p_tbl;
|
||||
UINT16 disc_rsn = AVDT_DISC_RSN_NORMAL;
|
||||
tAVDT_CCB *p_ccb;
|
||||
AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d\n",
|
||||
lcid, ack_needed);
|
||||
/* look up info for this channel */
|
||||
@@ -420,7 +421,13 @@ void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
|
||||
/* send L2CAP disconnect response */
|
||||
L2CA_DisconnectRsp(lcid);
|
||||
} else {
|
||||
disc_rsn = AVDT_DISC_RSN_ABNORMAL;
|
||||
if ((p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx)) != NULL) {
|
||||
UINT16 rsn = L2CA_GetDisconnectReason(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
|
||||
if (rsn != 0 && rsn != HCI_ERR_PEER_USER) {
|
||||
disc_rsn = AVDT_DISC_RSN_ABNORMAL;
|
||||
AVDT_TRACE_EVENT("avdt link disc rsn 0x%x", rsn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
avdt_ad_tc_close_ind(p_tbl, disc_rsn);
|
||||
|
||||
@@ -335,7 +335,7 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
|
||||
btsnd_hcic_ble_read_remote_feat(p->hci_handle);
|
||||
} else if (HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array)
|
||||
&& link_role == HCI_ROLE_SLAVE) {
|
||||
btsnd_hcic_ble_read_remote_feat(p->hci_handle);
|
||||
btsnd_hcic_rmt_ver_req (p->hci_handle);
|
||||
} else {
|
||||
btm_establish_continue(p);
|
||||
}
|
||||
@@ -906,12 +906,17 @@ void btm_read_remote_version_complete (UINT8 *p)
|
||||
}
|
||||
#if BLE_INCLUDED == TRUE
|
||||
if (p_acl_cb->transport == BT_TRANSPORT_LE) {
|
||||
if (HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl_cb->peer_le_features)) {
|
||||
uint16_t data_length = controller_get_interface()->get_ble_default_data_packet_length();
|
||||
uint16_t data_txtime = controller_get_interface()->get_ble_default_data_packet_txtime();
|
||||
btsnd_hcic_ble_set_data_length(p_acl_cb->hci_handle, data_length, data_txtime);
|
||||
if(p_acl_cb->link_role == HCI_ROLE_MASTER) {
|
||||
if (HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl_cb->peer_le_features)) {
|
||||
uint16_t data_length = controller_get_interface()->get_ble_default_data_packet_length();
|
||||
uint16_t data_txtime = controller_get_interface()->get_ble_default_data_packet_txtime();
|
||||
btsnd_hcic_ble_set_data_length(p_acl_cb->hci_handle, data_length, data_txtime);
|
||||
}
|
||||
l2cble_notify_le_connection (p_acl_cb->remote_addr);
|
||||
} else {
|
||||
//slave role, read remote feature
|
||||
btsnd_hcic_ble_read_remote_feat(p_acl_cb->hci_handle);
|
||||
}
|
||||
l2cble_notify_le_connection (p_acl_cb->remote_addr);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -1225,7 +1225,7 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY
|
||||
|
||||
/* Set that link key is known since this shares field with BTM_SEC_FLAG_LKEY_KNOWN flag in btm_api.h*/
|
||||
p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
|
||||
if ( p_keys->pcsrk_key.sec_level == SMP_SEC_AUTHENTICATED) {
|
||||
if ( p_keys->lenc_key.sec_level == SMP_SEC_AUTHENTICATED) {
|
||||
p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
|
||||
} else {
|
||||
p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
|
||||
@@ -1942,14 +1942,6 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
|
||||
handle = HCID_GET_HANDLE (handle);
|
||||
|
||||
btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
|
||||
if(role == HCI_ROLE_SLAVE) {
|
||||
//clear p_cb->state, controller will stop adv when ble connected.
|
||||
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
if(p_cb) {
|
||||
p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
|
||||
p_cb->state = BTM_BLE_STOP_ADV;
|
||||
}
|
||||
}
|
||||
l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
|
||||
conn_latency, conn_timeout);
|
||||
|
||||
|
||||
@@ -403,7 +403,6 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT32 duration,
|
||||
BTM_BLE_DEFAULT_SFP);
|
||||
}
|
||||
|
||||
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
|
||||
status = btm_ble_start_scan();
|
||||
}
|
||||
|
||||
@@ -442,7 +441,6 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT32 duration,
|
||||
tBTM_STATUS BTM_BleScan(BOOLEAN start, UINT32 duration,
|
||||
tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb)
|
||||
{
|
||||
tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
|
||||
tBTM_STATUS status = BTM_WRONG_MODE;
|
||||
|
||||
if (!controller_get_interface()->supports_ble()) {
|
||||
@@ -467,7 +465,6 @@ tBTM_STATUS BTM_BleScan(BOOLEAN start, UINT32 duration,
|
||||
/* enable resolving list */
|
||||
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
|
||||
#endif
|
||||
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
|
||||
status = btm_ble_start_scan();
|
||||
}
|
||||
|
||||
@@ -1370,7 +1367,7 @@ void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_
|
||||
}
|
||||
|
||||
void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
|
||||
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, tBTM_BLE_SFP scan_filter_policy,
|
||||
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBTM_BLE_SFP scan_filter_policy,
|
||||
tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback)
|
||||
{
|
||||
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
@@ -1407,12 +1404,14 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
|
||||
|
||||
if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, max_scan_interval) &&
|
||||
BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, max_scan_window) &&
|
||||
(scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS)) {
|
||||
(scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS) &&
|
||||
(scan_duplicate_filter < BTM_BLE_SCAN_DUPLICATE_MAX)) {
|
||||
p_cb->scan_type = scan_mode;
|
||||
p_cb->scan_interval = scan_interval;
|
||||
p_cb->scan_window = scan_window;
|
||||
p_cb->sfp = scan_filter_policy;
|
||||
p_cb->scan_params_set = TRUE;
|
||||
p_cb->scan_duplicate_filter = scan_duplicate_filter;
|
||||
|
||||
btsnd_hcic_ble_set_scan_params(p_cb->scan_type, (UINT16)scan_interval,
|
||||
(UINT16)scan_window,
|
||||
@@ -2282,7 +2281,6 @@ tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration)
|
||||
/* enable IRK list */
|
||||
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
|
||||
#endif
|
||||
p_ble_cb->inq_var.scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
|
||||
status = btm_ble_start_scan();
|
||||
} else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) ||
|
||||
(p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) {
|
||||
@@ -2573,7 +2571,7 @@ static void btm_ble_parse_adv_data(tBTM_INQ_INFO *p_info, UINT8 *p_data,
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
|
||||
void btm_ble_cache_adv_data(BD_ADDR bda, tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
|
||||
{
|
||||
tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
UINT8 *p_cache;
|
||||
@@ -2585,6 +2583,15 @@ void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, U
|
||||
memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
|
||||
p_cur->adv_data_len = 0;
|
||||
p_cur->scan_rsp_len = 0;
|
||||
}
|
||||
|
||||
//Clear the adv cache if the addresses are not equal
|
||||
if(memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) != 0) {
|
||||
p_le_inq_cb->adv_len = 0;
|
||||
memcpy(p_le_inq_cb->adv_addr, bda, BD_ADDR_LEN);
|
||||
memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
|
||||
p_cur->adv_data_len = 0;
|
||||
p_cur->scan_rsp_len = 0;
|
||||
}
|
||||
|
||||
if (data_len > 0) {
|
||||
@@ -2814,7 +2821,7 @@ static void btm_ble_appearance_to_cod(UINT16 appearance, UINT8 *dev_class)
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
|
||||
BOOLEAN btm_ble_update_inq_result(BD_ADDR bda, tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
|
||||
{
|
||||
BOOLEAN to_report = TRUE;
|
||||
tBTM_INQ_RESULTS *p_cur = &p_i->inq_info.results;
|
||||
@@ -2832,7 +2839,7 @@ BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_t
|
||||
BTM_TRACE_WARNING("EIR data too long %d. discard", data_len);
|
||||
return FALSE;
|
||||
}
|
||||
btm_ble_cache_adv_data(p_cur, data_len, p, evt_type);
|
||||
btm_ble_cache_adv_data(bda, p_cur, data_len, p, evt_type);
|
||||
|
||||
p1 = (p + data_len);
|
||||
STREAM_TO_UINT8 (rssi, p1);
|
||||
@@ -3056,6 +3063,71 @@ void btm_ble_process_adv_pkt (UINT8 *p_data)
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btm_ble_process_last_adv_pkt
|
||||
**
|
||||
** Description This function is called to report last adv packet
|
||||
**
|
||||
** Parameters
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
||||
static void btm_ble_process_last_adv_pkt(void)
|
||||
{
|
||||
UINT8 result = 0;
|
||||
UINT8 null_bda[6] = {0};
|
||||
tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
|
||||
tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
|
||||
tBTM_INQ_RESULTS_CB *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
|
||||
tBTM_INQ_RESULTS_CB *p_scan_results_cb = btm_cb.ble_ctr_cb.p_scan_results_cb;
|
||||
tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
tINQ_DB_ENT *p_i = btm_inq_db_find (p_le_inq_cb->adv_addr);
|
||||
|
||||
if(memcmp(null_bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(p_i == NULL) {
|
||||
BTM_TRACE_DEBUG("no last adv");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((result = btm_ble_is_discoverable(p_le_inq_cb->adv_addr, p_i->inq_info.results.ble_evt_type, NULL)) == 0) {
|
||||
BTM_TRACE_WARNING("%s device is no longer discoverable so discarding advertising packet pkt",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
/* background connection in selective connection mode */
|
||||
if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
|
||||
//do nothing
|
||||
} else {
|
||||
if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
|
||||
(p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
|
||||
p_le_inq_cb->adv_len = 0;
|
||||
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
|
||||
p_i->inq_info.results.adv_data_len = 0;
|
||||
p_i->inq_info.results.scan_rsp_len = 0;
|
||||
}
|
||||
if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
|
||||
(p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
|
||||
p_le_inq_cb->adv_len = 0;
|
||||
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
|
||||
p_i->inq_info.results.adv_data_len = 0;
|
||||
p_i->inq_info.results.scan_rsp_len = 0;
|
||||
}
|
||||
if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
|
||||
(p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
|
||||
p_le_inq_cb->adv_len = 0;
|
||||
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
|
||||
p_i->inq_info.results.adv_data_len = 0;
|
||||
p_i->inq_info.results.scan_rsp_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btm_ble_process_adv_pkt_cont
|
||||
@@ -3080,6 +3152,13 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
|
||||
BOOLEAN update = TRUE;
|
||||
UINT8 result = 0;
|
||||
|
||||
//if scan duplicate is enabled, the adv packet without scan response is allowed to report to upper layer
|
||||
if(p_le_inq_cb->scan_duplicate_filter == BTM_BLE_SCAN_DUPLICATE_ENABLE) {
|
||||
if(memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) != 0) {
|
||||
btm_ble_process_last_adv_pkt();
|
||||
}
|
||||
}
|
||||
|
||||
p_i = btm_inq_db_find (bda);
|
||||
|
||||
/* Check if this address has already been processed for this inquiry */
|
||||
@@ -3108,7 +3187,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
|
||||
p_inq->inq_cmpl_info.num_resp++;
|
||||
}
|
||||
/* update the LE device information in inquiry database */
|
||||
if (!btm_ble_update_inq_result(p_i, addr_type, evt_type, p)) {
|
||||
if (!btm_ble_update_inq_result(bda, p_i, addr_type, evt_type, p)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3152,12 +3231,24 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
|
||||
} else {
|
||||
if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
|
||||
(p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
|
||||
p_le_inq_cb->adv_len = 0;
|
||||
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
|
||||
p_i->inq_info.results.adv_data_len = 0;
|
||||
p_i->inq_info.results.scan_rsp_len = 0;
|
||||
}
|
||||
if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
|
||||
(p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
|
||||
p_le_inq_cb->adv_len = 0;
|
||||
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
|
||||
p_i->inq_info.results.adv_data_len = 0;
|
||||
p_i->inq_info.results.scan_rsp_len = 0;
|
||||
}
|
||||
if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
|
||||
(p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
|
||||
p_le_inq_cb->adv_len = 0;
|
||||
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
|
||||
p_i->inq_info.results.adv_data_len = 0;
|
||||
p_i->inq_info.results.scan_rsp_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3196,6 +3287,9 @@ tBTM_STATUS btm_ble_start_scan(void)
|
||||
tBTM_STATUS status = BTM_CMD_STARTED;
|
||||
// recoverly the scan parameters to the controller before start scan
|
||||
btm_ble_recover_scan_params();
|
||||
if(p_inq->scan_duplicate_filter > BTM_BLE_DUPLICATE_MAX) {
|
||||
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
|
||||
}
|
||||
/* start scan, disable duplicate filtering */
|
||||
if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)) {
|
||||
status = BTM_NO_RESOURCES;
|
||||
|
||||
@@ -1361,7 +1361,7 @@ tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_SE
|
||||
|
||||
return (BTM_SUCCESS);
|
||||
}
|
||||
|
||||
p_dev_rec->enc_init_by_we = TRUE;
|
||||
/* enqueue security request if security is active */
|
||||
if (p_dev_rec->p_callback || (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE)) {
|
||||
BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption busy, enqueue request\n");
|
||||
@@ -4537,7 +4537,7 @@ void btm_sec_disconnected (UINT16 handle, UINT8 reason)
|
||||
if (!p_dev_rec) {
|
||||
return;
|
||||
}
|
||||
|
||||
p_dev_rec->enc_init_by_we = FALSE;
|
||||
transport = (handle == p_dev_rec->hci_handle) ? BT_TRANSPORT_BR_EDR : BT_TRANSPORT_LE;
|
||||
|
||||
p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
|
||||
|
||||
@@ -906,7 +906,30 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l
|
||||
case HCI_BLE_CLEAR_WHITE_LIST:
|
||||
btm_ble_clear_white_list_complete(p, evt_len);
|
||||
break;
|
||||
|
||||
case HCI_BLE_WRITE_ADV_PARAMS: {
|
||||
uint8_t status;
|
||||
STREAM_TO_UINT8 (status, p);
|
||||
if(status != HCI_SUCCESS) {
|
||||
HCI_TRACE_ERROR("hci write adv params error 0x%x", status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HCI_BLE_RC_PARAM_REQ_REPLY: {
|
||||
uint8_t status;
|
||||
STREAM_TO_UINT8 (status, p);
|
||||
if(status != HCI_SUCCESS) {
|
||||
HCI_TRACE_ERROR("hci connection params reply command error 0x%x", status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HCI_BLE_RC_PARAM_REQ_NEG_REPLY: {
|
||||
uint8_t status;
|
||||
STREAM_TO_UINT8 (status, p);
|
||||
if(status != HCI_SUCCESS) {
|
||||
HCI_TRACE_ERROR("hci connection params neg reply command error 0x%x", status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HCI_BLE_REMOVE_WHITE_LIST:
|
||||
btm_ble_remove_from_white_list_complete(p, evt_len);
|
||||
break;
|
||||
|
||||
@@ -239,23 +239,6 @@ void btu_task_thread_handler(void *arg)
|
||||
case SIG_BTU_ONESHOT_ALARM: {
|
||||
TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)e.par;
|
||||
btu_general_alarm_process(p_tle);
|
||||
|
||||
switch (p_tle->event) {
|
||||
#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
|
||||
case BTU_TTYPE_BLE_RANDOM_ADDR:
|
||||
btm_ble_timeout(p_tle);
|
||||
break;
|
||||
#endif
|
||||
case BTU_TTYPE_USER_FUNC: {
|
||||
tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
|
||||
(*p_uf)(p_tle);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// FAIL
|
||||
LOG_ERROR("Received unexpected oneshot timer event:0x%x\n", p_tle->event);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIG_BTU_L2CAP_ALARM:
|
||||
|
||||
@@ -1038,7 +1038,10 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
|
||||
if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) {
|
||||
sent = TRUE;
|
||||
p_cmd->to_send = FALSE;
|
||||
p_cmd->p_cmd = NULL;
|
||||
if(p_cmd->p_cmd) {
|
||||
osi_free(p_cmd->p_cmd);
|
||||
p_cmd->p_cmd = NULL;
|
||||
}
|
||||
|
||||
/* dequeue the request if is write command or sign write */
|
||||
if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE) {
|
||||
|
||||
@@ -2258,6 +2258,7 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport)
|
||||
GATT_TRACE_DEBUG ("exit gatt_cleanup_upon_disc ");
|
||||
BTM_Recovery_Pre_State();
|
||||
}
|
||||
gatt_delete_dev_from_srv_chg_clt_list(bda);
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
||||
@@ -573,6 +573,12 @@ typedef struct {
|
||||
tBTM_BLE_REF_VALUE ref_value;
|
||||
} tBTM_BLE_BATCH_SCAN_CB;
|
||||
|
||||
/// Ble scan duplicate type
|
||||
enum {
|
||||
BTM_BLE_SCAN_DUPLICATE_DISABLE = 0x0, /*!< the Link Layer should generate advertising reports to the host for each packet received */
|
||||
BTM_BLE_SCAN_DUPLICATE_ENABLE = 0x1, /*!< the Link Layer should filter out duplicate advertising reports to the Host */
|
||||
BTM_BLE_SCAN_DUPLICATE_MAX = 0x2, /*!< 0x02 – 0xFF, Reserved for future use */
|
||||
};
|
||||
/* filter selection bit index */
|
||||
#define BTM_BLE_PF_ADDR_FILTER 0
|
||||
#define BTM_BLE_PF_SRVC_DATA 1
|
||||
@@ -1050,6 +1056,7 @@ void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
** scan_window - Scan window
|
||||
** scan_type - Scan type
|
||||
** addr_type_own - owner address type
|
||||
** scan_duplicate_filter - scan duplicate filter
|
||||
** scan_filter_policy - scan filter policy
|
||||
** scan_setup_status_cback - Scan setup status callback
|
||||
**
|
||||
@@ -1057,7 +1064,7 @@ void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
|
||||
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, tBTM_BLE_SFP scan_filter_policy,
|
||||
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBTM_BLE_SFP scan_filter_policy,
|
||||
tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback);
|
||||
|
||||
|
||||
|
||||
@@ -55,8 +55,9 @@
|
||||
|
||||
#define BTM_BLE_ENC_MASK 0x03
|
||||
|
||||
#define BTM_BLE_DUPLICATE_ENABLE 1
|
||||
#define BTM_BLE_DUPLICATE_DISABLE 0
|
||||
#define BTM_BLE_DUPLICATE_ENABLE 1
|
||||
#define BTM_BLE_DUPLICATE_MAX BTM_BLE_DUPLICATE_ENABLE
|
||||
|
||||
#define BTM_BLE_GAP_DISC_SCAN_INT 18 /* Interval(scan_int) = 11.25 ms= 0x0010 * 0.625 ms */
|
||||
#define BTM_BLE_GAP_DISC_SCAN_WIN 18 /* scan_window = 11.25 ms= 0x0010 * 0.625 ms */
|
||||
@@ -161,7 +162,7 @@ typedef struct {
|
||||
|
||||
UINT8 adv_len;
|
||||
UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX];
|
||||
|
||||
BD_ADDR adv_addr;
|
||||
/* inquiry BD addr database */
|
||||
UINT8 num_bd_entries;
|
||||
UINT8 max_bd_entries;
|
||||
|
||||
@@ -614,7 +614,7 @@ typedef struct {
|
||||
// btla-specific --
|
||||
#define BTM_SEC_NO_LAST_SERVICE_ID 0
|
||||
UINT8 last_author_service_id; /* ID of last serviced authorized: Reset after each l2cap connection */
|
||||
|
||||
BOOLEAN enc_init_by_we;
|
||||
} tBTM_SEC_DEV_REC;
|
||||
|
||||
#define BTM_SEC_IS_SM4(sm) ((BOOLEAN)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
|
||||
|
||||
@@ -1876,7 +1876,7 @@ BOOLEAN L2CA_RemoveFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda)
|
||||
p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport);
|
||||
|
||||
if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) ) {
|
||||
L2CAP_TRACE_WARNING ("L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x not connected", fixed_cid,
|
||||
L2CAP_TRACE_DEBUG ("L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x not connected", fixed_cid,
|
||||
(rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3], (rem_bda[4] << 8) + rem_bda[5]);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
@@ -261,6 +261,15 @@ void l2cble_notify_le_connection (BD_ADDR bda)
|
||||
tACL_CONN *p_acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE) ;
|
||||
|
||||
if (p_lcb != NULL && p_acl != NULL && p_lcb->link_state != LST_CONNECTED) {
|
||||
|
||||
if(p_acl->link_role == HCI_ROLE_SLAVE) {
|
||||
//clear p_cb->state, controller will stop adv when ble connected.
|
||||
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
if(p_cb) {
|
||||
p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
|
||||
p_cb->state = BTM_BLE_STOP_ADV;
|
||||
}
|
||||
}
|
||||
/* update link status */
|
||||
btm_establish_continue(p_acl);
|
||||
/* update l2cap link status and send callback */
|
||||
|
||||
@@ -58,6 +58,8 @@ extern elliptic_curve_t curve_p256;
|
||||
|
||||
void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
|
||||
|
||||
bool ECC_CheckPointIsInElliCur_P256(Point *p);
|
||||
|
||||
#define ECC_PointMult(q, p, n, keyLength) ECC_PointMult_Bin_NAF(q, p, n, keyLength)
|
||||
|
||||
void p_256_init_curve(UINT32 keyLength);
|
||||
|
||||
@@ -240,4 +240,39 @@ void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength)
|
||||
multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
|
||||
}
|
||||
|
||||
bool ECC_CheckPointIsInElliCur_P256(Point *p)
|
||||
{
|
||||
/* y^2 % q */
|
||||
DWORD y_y_q[KEY_LENGTH_DWORDS_P256] = {0x0};
|
||||
/* x^2 % q */
|
||||
DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
|
||||
/* x % q */
|
||||
DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
|
||||
/* x^2, To prevent overflow, the length of the x square here needs to
|
||||
be expanded to two times the original one. */
|
||||
DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0};
|
||||
/* y_y_q =(p->y)^2(mod q) */
|
||||
multiprecision_mersenns_squa_mod(y_y_q, p->y, KEY_LENGTH_DWORDS_P256);
|
||||
/* Calculate the value of p->x square, x_x = (p->x)^2 */
|
||||
multiprecision_mult(x_x, p->x, p->x, KEY_LENGTH_DWORDS_P256);
|
||||
/* The function of the elliptic curve is y^2 = x^3 - 3x + b (mod q) ==>
|
||||
y^2 = (x^2 - 3)*x + b (mod q),
|
||||
so we calculate the x^2 - 3 value here */
|
||||
x_x[0] -= 3;
|
||||
/* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==>
|
||||
(x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */
|
||||
multiprecision_fast_mod_P256(x_x_q, x_x);
|
||||
/* x_x = x_x_q * x_q */
|
||||
multiprecision_mult(x_x, x_x_q, p->x, KEY_LENGTH_DWORDS_P256);
|
||||
/* x_q = x_x % q */
|
||||
multiprecision_fast_mod_P256(x_q, x_x);
|
||||
/* Save the result in x_x_q */
|
||||
multiprecision_add_mod(x_x_q, x_q, curve_p256.b, KEY_LENGTH_DWORDS_P256);
|
||||
/* compare the y_y_q and x_x_q, see if they are on a given elliptic curve. */
|
||||
if (multiprecision_compare(y_y_q, x_x_q, KEY_LENGTH_DWORDS_P256)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "btm_int.h"
|
||||
#include "l2c_api.h"
|
||||
#include "smp_int.h"
|
||||
#include "p_256_ecc_pp.h"
|
||||
//#include "utils/include/bt_utils.h"
|
||||
|
||||
#if SMP_INCLUDED == TRUE
|
||||
@@ -58,7 +59,7 @@ static bool lmp_version_below(BD_ADDR bda, uint8_t version)
|
||||
SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__);
|
||||
return false;
|
||||
}
|
||||
SMP_TRACE_WARNING("%s LMP version %d < %d", __func__, acl->lmp_version, version);
|
||||
SMP_TRACE_DEBUG("%s LMP version %d < %d", __func__, acl->lmp_version, version);
|
||||
return acl->lmp_version < version;
|
||||
}
|
||||
|
||||
@@ -668,6 +669,12 @@ void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
|
||||
STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
|
||||
STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
|
||||
/* In order to prevent the x and y coordinates of the public key from being modified,
|
||||
we need to check whether the x and y coordinates are on the given elliptic curve. */
|
||||
if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) {
|
||||
SMP_TRACE_ERROR("%s, Invalid Public key.", __func__);
|
||||
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
|
||||
}
|
||||
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
|
||||
|
||||
smp_wait_for_both_public_keys(p_cb, NULL);
|
||||
@@ -1826,7 +1833,7 @@ void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable)
|
||||
{
|
||||
tSMP_CB *p_cb = &smp_cb;
|
||||
|
||||
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
|
||||
SMP_TRACE_DEBUG("%s encr_enable=%d\n", __func__, encr_enable);
|
||||
|
||||
if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0) {
|
||||
@@ -1837,6 +1844,16 @@ void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable)
|
||||
btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size);
|
||||
}
|
||||
|
||||
smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
|
||||
} else if (p_dev_rec && !p_dev_rec->enc_init_by_we) {
|
||||
/*
|
||||
if enc_init_by_we is false, it means that client initiates encryption before slave calls esp_ble_set_encryption()
|
||||
we need initiate pairing_bda and p_cb->role then encryption, for example iPhones
|
||||
*/
|
||||
memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN);
|
||||
p_cb->state = SMP_STATE_ENCRYPTION_PENDING;
|
||||
p_cb->role = HCI_ROLE_SLAVE;
|
||||
p_dev_rec->enc_init_by_we = FALSE;
|
||||
smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,10 @@ static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN conne
|
||||
if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!connected && &p_cb->rsp_timer_ent) {
|
||||
//free timer
|
||||
btu_free_timer(&p_cb->rsp_timer_ent);
|
||||
}
|
||||
if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
|
||||
SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s\n",
|
||||
__FUNCTION__,
|
||||
|
||||
@@ -50,14 +50,16 @@
|
||||
#define BTDM_CFG_BT_DATA_RELEASE (1<<0)
|
||||
#define BTDM_CFG_HCI_UART (1<<1)
|
||||
#define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<2)
|
||||
#define BTDM_CFG_SCAN_DUPLICATE_OPTIONS (1<<3)
|
||||
#define BTDM_CFG_SEND_ADV_RESERVED_SIZE (1<<4)
|
||||
/* Other reserved for future */
|
||||
|
||||
/* not for user call, so don't put to include file */
|
||||
extern void btdm_osi_funcs_register(void *osi_funcs);
|
||||
extern int btdm_controller_init(uint32_t config_mask, esp_bt_controller_config_t *config_opts);
|
||||
extern int btdm_controller_deinit(void);
|
||||
extern void btdm_controller_deinit(void);
|
||||
extern int btdm_controller_enable(esp_bt_mode_t mode);
|
||||
extern int btdm_controller_disable(esp_bt_mode_t mode);
|
||||
extern void btdm_controller_disable(void);
|
||||
extern uint8_t btdm_controller_get_mode(void);
|
||||
extern const char *btdm_controller_get_compile_version(void);
|
||||
extern void btdm_rf_bb_init(void);
|
||||
@@ -600,6 +602,10 @@ static uint32_t btdm_config_mask_load(void)
|
||||
#if CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE == 1
|
||||
mask |= BTDM_CFG_CONTROLLER_RUN_APP_CPU;
|
||||
#endif
|
||||
mask |= BTDM_CFG_SCAN_DUPLICATE_OPTIONS;
|
||||
|
||||
mask |= BTDM_CFG_SEND_ADV_RESERVED_SIZE;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
@@ -742,9 +748,7 @@ esp_err_t esp_bt_controller_deinit(void)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (btdm_controller_deinit() != 0) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
btdm_controller_deinit();
|
||||
|
||||
periph_module_disable(PERIPH_BT_MODULE);
|
||||
|
||||
@@ -800,21 +804,14 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
|
||||
|
||||
esp_err_t esp_bt_controller_disable(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ret = btdm_controller_disable(btdm_controller_get_mode());
|
||||
if (ret < 0) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
btdm_controller_disable();
|
||||
|
||||
if (ret == ESP_BT_MODE_IDLE) {
|
||||
esp_phy_rf_deinit();
|
||||
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
|
||||
}
|
||||
esp_phy_rf_deinit();
|
||||
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(s_pm_lock);
|
||||
|
||||
@@ -35,9 +35,19 @@ typedef struct {
|
||||
uint8_t controller_task_prio; /*!< Bluetooth controller task priority */
|
||||
uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */
|
||||
uint32_t hci_uart_baudrate; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
|
||||
uint8_t scan_duplicate_mode; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
|
||||
uint16_t normal_adv_size; /*!< Normal adv size for scan duplicate */
|
||||
uint16_t mesh_adv_size; /*!< Mesh adv size for scan duplicate */
|
||||
uint16_t send_adv_reserved_size; /*!< Controller minimum memory value */
|
||||
uint32_t controller_debug_flag; /*!< Controller debug log flag */
|
||||
} esp_bt_controller_config_t;
|
||||
|
||||
#ifdef CONFIG_BT_ENABLED
|
||||
/* While scanning, if the free memory value in controller is less than SCAN_SEND_ADV_RESERVED_SIZE,
|
||||
the adv packet will be discarded until the memory is restored. */
|
||||
#define SCAN_SEND_ADV_RESERVED_SIZE 1000
|
||||
/* open controller log debug when adv lost */
|
||||
#define CONTROLLER_ADV_LOST_DEBUG_BIT (0<<0)
|
||||
|
||||
#ifdef CONFIG_BT_HCI_UART_NO
|
||||
#define BT_HCI_UART_NO_DEFAULT CONFIG_BT_HCI_UART_NO
|
||||
@@ -51,11 +61,42 @@ typedef struct {
|
||||
#define BT_HCI_UART_BAUDRATE_DEFAULT 921600
|
||||
#endif /* BT_HCI_UART_BAUDRATE_DEFAULT */
|
||||
|
||||
/* normal adv cache size */
|
||||
#ifdef CONFIG_DUPLICATE_SCAN_CACHE_SIZE
|
||||
#define NORMAL_SCAN_DUPLICATE_CACHE_SIZE CONFIG_DUPLICATE_SCAN_CACHE_SIZE
|
||||
#else
|
||||
#define NORMAL_SCAN_DUPLICATE_CACHE_SIZE 20
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BLE_MESH_SCAN_DUPLICATE_EN
|
||||
#define CONFIG_BLE_MESH_SCAN_DUPLICATE_EN FALSE
|
||||
#endif
|
||||
|
||||
#define SCAN_DUPLICATE_MODE_NORMAL_ADV_ONLY 0
|
||||
#define SCAN_DUPLICATE_MODE_NORMAL_ADV_MESH_ADV 1
|
||||
|
||||
#if CONFIG_BLE_MESH_SCAN_DUPLICATE_EN
|
||||
#define SCAN_DUPLICATE_MODE SCAN_DUPLICATE_MODE_NORMAL_ADV_MESH_ADV
|
||||
#ifdef CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE
|
||||
#define MESH_DUPLICATE_SCAN_CACHE_SIZE CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE
|
||||
#else
|
||||
#define MESH_DUPLICATE_SCAN_CACHE_SIZE 50
|
||||
#endif
|
||||
#else
|
||||
#define SCAN_DUPLICATE_MODE SCAN_DUPLICATE_MODE_NORMAL_ADV_ONLY
|
||||
#define MESH_DUPLICATE_SCAN_CACHE_SIZE 0
|
||||
#endif
|
||||
|
||||
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \
|
||||
.controller_task_stack_size = ESP_TASK_BT_CONTROLLER_STACK, \
|
||||
.controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
|
||||
.hci_uart_no = BT_HCI_UART_NO_DEFAULT, \
|
||||
.hci_uart_baudrate = BT_HCI_UART_BAUDRATE_DEFAULT, \
|
||||
.scan_duplicate_mode = SCAN_DUPLICATE_MODE, \
|
||||
.normal_adv_size = NORMAL_SCAN_DUPLICATE_CACHE_SIZE, \
|
||||
.mesh_adv_size = MESH_DUPLICATE_SCAN_CACHE_SIZE, \
|
||||
.send_adv_reserved_size = SCAN_SEND_ADV_RESERVED_SIZE, \
|
||||
.controller_debug_flag = CONTROLLER_ADV_LOST_DEBUG_BIT, \
|
||||
};
|
||||
#else
|
||||
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() {0}; _Static_assert(0, "please enable bluetooth in menuconfig to use bt.h");
|
||||
|
||||
Submodule components/bt/lib updated: b76cf6aa30...96e7e06e0b
73
components/driver/adc1_i2s_private.h
Normal file
73
components/driver/adc1_i2s_private.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2015-2016 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.
|
||||
|
||||
#ifndef _DRIVER_ADC1_I2S_PRIVATE_H_
|
||||
#define _DRIVER_ADC1_I2S_PRIVATE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Force power on for SAR ADC.
|
||||
* This function should be called for the scenario in which ADC are controlled by digital function like DMA.
|
||||
* When the ADC power is always on, RTC FSM can still be functional.
|
||||
* This is an internal API for I2S module to call to enable I2S-ADC function.
|
||||
* Note that adc_power_off() can still power down ADC.
|
||||
*/
|
||||
void adc_power_always_on();
|
||||
|
||||
/**
|
||||
* @brief For I2S dma to claim the usage of ADC1.
|
||||
*
|
||||
* Other tasks will be forbidden to use ADC1 between ``adc1_i2s_mode_acquire`` and ``adc1_i2s_release``.
|
||||
* The I2S module may have to wait for a short time for the current conversion (if exist) to finish.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
|
||||
*/
|
||||
esp_err_t adc1_i2s_mode_acquire();
|
||||
|
||||
/**
|
||||
* @brief For ADC1 to claim the usage of ADC1.
|
||||
*
|
||||
* Other tasks will be forbidden to use ADC1 between ``adc1_adc_mode_acquire`` and ``adc1_i2s_release``.
|
||||
* The ADC1 may have to wait for some time for the I2S read operation to finish.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
|
||||
*/
|
||||
esp_err_t adc1_adc_mode_acquire();
|
||||
|
||||
/**
|
||||
* @brief to let other tasks use the ADC1 when I2S is not work.
|
||||
*
|
||||
* Other tasks will be forbidden to use ADC1 between ``adc1_adc/i2s_mode_acquire`` and ``adc1_i2s_release``.
|
||||
* Call this function to release the occupation of ADC1
|
||||
*
|
||||
* @return always return ESP_OK.
|
||||
*/
|
||||
esp_err_t adc1_lock_release();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_DRIVER_ADC1_I2S_PRIVATE_H_*/
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "driver/dac.h"
|
||||
#include "adc1_i2s_private.h"
|
||||
|
||||
#include "esp_intr.h"
|
||||
#include "esp_err.h"
|
||||
@@ -84,12 +85,14 @@ typedef struct {
|
||||
int bits_per_sample; /*!< Bits per sample*/
|
||||
i2s_mode_t mode; /*!< I2S Working mode*/
|
||||
int use_apll; /*!< I2S use APLL clock */
|
||||
uint32_t sample_rate; /*!< I2S sample rate */
|
||||
} i2s_obj_t;
|
||||
|
||||
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
|
||||
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
|
||||
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
|
||||
|
||||
static int _i2s_adc_unit = -1;
|
||||
static int _i2s_adc_channel = -1;
|
||||
/**
|
||||
* @brief Pre define APLL parameters, save compute time
|
||||
* | bits_per_sample | rate | sdm0 | sdm1 | sdm2 | odir
|
||||
@@ -322,12 +325,11 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
||||
if (p_i2s_obj[i2s_num] == NULL) {
|
||||
ESP_LOGE(I2S_TAG, "Not initialized yet");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
p_i2s_obj[i2s_num]->sample_rate = rate;
|
||||
double clkmdiv = (double)I2S_BASE_CLK / (rate * factor);
|
||||
|
||||
if (clkmdiv > 256) {
|
||||
@@ -652,6 +654,18 @@ esp_err_t i2s_start(i2s_port_t i2s_num)
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||
//start DMA link
|
||||
I2S_ENTER_CRITICAL();
|
||||
i2s_reset_fifo(i2s_num);
|
||||
//reset dma
|
||||
I2S[i2s_num]->lc_conf.in_rst = 1;
|
||||
I2S[i2s_num]->lc_conf.in_rst = 0;
|
||||
I2S[i2s_num]->lc_conf.out_rst = 1;
|
||||
I2S[i2s_num]->lc_conf.out_rst = 0;
|
||||
|
||||
I2S[i2s_num]->conf.tx_reset = 1;
|
||||
I2S[i2s_num]->conf.tx_reset = 0;
|
||||
I2S[i2s_num]->conf.rx_reset = 1;
|
||||
I2S[i2s_num]->conf.rx_reset = 0;
|
||||
|
||||
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
|
||||
I2S[i2s_num]->int_clr.val = 0xFFFFFFFF;
|
||||
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
|
||||
@@ -685,17 +699,6 @@ esp_err_t i2s_stop(i2s_port_t i2s_num)
|
||||
i2s_disable_rx_intr(i2s_num);
|
||||
}
|
||||
I2S[i2s_num]->int_clr.val = I2S[i2s_num]->int_st.val; //clear pending interrupt
|
||||
i2s_reset_fifo(i2s_num);
|
||||
//reset dma
|
||||
I2S[i2s_num]->lc_conf.in_rst = 1;
|
||||
I2S[i2s_num]->lc_conf.in_rst = 0;
|
||||
I2S[i2s_num]->lc_conf.out_rst = 1;
|
||||
I2S[i2s_num]->lc_conf.out_rst = 0;
|
||||
|
||||
I2S[i2s_num]->conf.tx_reset = 1;
|
||||
I2S[i2s_num]->conf.tx_reset = 0;
|
||||
I2S[i2s_num]->conf.rx_reset = 1;
|
||||
I2S[i2s_num]->conf.rx_reset = 0;
|
||||
I2S_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -722,10 +725,18 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t _i2s_adc_mode_recover()
|
||||
{
|
||||
I2S_CHECK(((_i2s_adc_unit != -1) && (_i2s_adc_channel != -1)), "i2s ADC recover error, not initialized...", ESP_ERR_INVALID_ARG);
|
||||
return adc_i2s_mode_init(_i2s_adc_unit, _i2s_adc_channel);
|
||||
}
|
||||
|
||||
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel)
|
||||
{
|
||||
I2S_CHECK((adc_unit < ADC_UNIT_2), "i2s ADC unit error, only support ADC1 for now", ESP_ERR_INVALID_ARG);
|
||||
// For now, we only support SAR ADC1.
|
||||
_i2s_adc_unit = adc_unit;
|
||||
_i2s_adc_channel = adc_channel;
|
||||
return adc_i2s_mode_init(adc_unit, adc_channel);
|
||||
}
|
||||
|
||||
@@ -864,7 +875,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
|
||||
//initialize the specific ADC channel.
|
||||
//in the current stage, we only support ADC1 and single channel mode.
|
||||
//In default data mode, the ADC data is in 12-bit resolution mode.
|
||||
adc_power_on();
|
||||
adc_power_always_on();
|
||||
}
|
||||
// configure I2S data port interface.
|
||||
i2s_reset_fifo(i2s_num);
|
||||
@@ -1171,6 +1182,27 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2s_adc_enable(i2s_port_t i2s_num)
|
||||
{
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE);
|
||||
|
||||
adc1_i2s_mode_acquire();
|
||||
_i2s_adc_mode_recover();
|
||||
return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num);
|
||||
}
|
||||
|
||||
esp_err_t i2s_adc_disable(i2s_port_t i2s_num)
|
||||
{
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE);
|
||||
|
||||
adc1_lock_release();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait)
|
||||
{
|
||||
char *data_ptr;
|
||||
|
||||
@@ -204,12 +204,13 @@ int adc1_get_voltage(adc1_channel_t channel) __attribute__((deprecated));
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Power on SAR ADC
|
||||
* @brief Enable ADC power
|
||||
*/
|
||||
void adc_power_on();
|
||||
|
||||
/**
|
||||
* @brief Power off SAR ADC
|
||||
* This function will force power down for ADC
|
||||
*/
|
||||
void adc_power_off();
|
||||
|
||||
|
||||
@@ -353,6 +353,8 @@ int i2s_read_bytes(i2s_port_t i2s_num, void *dest, size_t size, TickType_t ticks
|
||||
*
|
||||
* @note If the built-in ADC mode is enabled, we should call i2s_adc_start and i2s_adc_stop around the whole reading process,
|
||||
* to prevent the data getting corrupted.
|
||||
* @note If the built-in ADC mode is enabled, we should call i2s_adc_start and i2s_adc_stop around the whole reading process,
|
||||
* to prevent the data getting corrupted.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
@@ -485,6 +487,31 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
*/
|
||||
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel);
|
||||
|
||||
/**
|
||||
* @brief Start to use I2S built-in ADC mode
|
||||
* @note This function would acquire the lock of ADC to prevent the data getting corrupted
|
||||
* during the I2S peripheral is being used to do fully continuous ADC sampling.
|
||||
*
|
||||
* @param i2s_num i2s port index
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_INVALID_STATE driver state error
|
||||
* - ESP_FAIL Internal driver error
|
||||
*/
|
||||
esp_err_t i2s_adc_enable(i2s_port_t i2s_num);
|
||||
|
||||
/**
|
||||
* @brief Stop to use I2S built-in ADC mode
|
||||
* @param i2s_num i2s port index
|
||||
* @note This function would release the lock of ADC so that other tasks can use ADC.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_INVALID_STATE driver state error
|
||||
*/
|
||||
esp_err_t i2s_adc_disable(i2s_port_t i2s_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "sys/lock.h"
|
||||
#include "driver/rtc_cntl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "adc1_i2s_private.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Enable built-in checks in queue.h in debug builds
|
||||
@@ -99,6 +100,9 @@ static _lock_t adc2_wifi_lock = NULL;
|
||||
//prevent ADC2 being used by tasks (regardless of WIFI)
|
||||
portMUX_TYPE adc2_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
//prevent ADC1 being used by I2S dma and other tasks at the same time.
|
||||
static _lock_t adc1_i2s_lock = NULL;
|
||||
|
||||
typedef struct {
|
||||
TimerHandle_t timer;
|
||||
uint32_t filtered_val[TOUCH_PAD_MAX];
|
||||
@@ -108,12 +112,6 @@ typedef struct {
|
||||
} touch_pad_filter_t;
|
||||
static touch_pad_filter_t *s_touch_pad_filter = NULL;
|
||||
|
||||
typedef enum {
|
||||
ADC_FORCE_FSM = 0x0,
|
||||
ADC_FORCE_DISABLE = 0x2,
|
||||
ADC_FORCE_ENABLE = 0x3,
|
||||
} adc_force_mode_t;
|
||||
|
||||
//Reg,Mux,Fun,IE,Up,Down,Rtc_number
|
||||
const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
|
||||
{RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, RTC_IO_TOUCH_PAD1_HOLD_M, RTC_CNTL_TOUCH_PAD1_HOLD_FORCE_M, RTC_IO_TOUCH_PAD1_DRV_V, RTC_IO_TOUCH_PAD1_DRV_S, RTCIO_GPIO0_CHANNEL}, //0
|
||||
@@ -1025,10 +1023,21 @@ static esp_err_t adc_set_atten(adc_unit_t adc_unit, adc_channel_t channel, adc_a
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void adc_power_always_on()
|
||||
{
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU;
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
}
|
||||
|
||||
void adc_power_on()
|
||||
{
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_FSM;
|
||||
if (SENS.sar_meas_wait2.force_xpd_sar & SENS_FORCE_XPD_SAR_SW_M) {
|
||||
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU;
|
||||
} else {
|
||||
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_FSM;
|
||||
}
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
}
|
||||
|
||||
@@ -1037,7 +1046,7 @@ void adc_power_off()
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
//Bit1 0:Fsm 1: SW mode
|
||||
//Bit0 0:SW mode power down 1: SW mode power on
|
||||
SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_DISABLE;
|
||||
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PD;
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
}
|
||||
|
||||
@@ -1161,7 +1170,7 @@ esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
|
||||
uint8_t table_len = 1;
|
||||
//POWER ON SAR
|
||||
adc_power_on();
|
||||
adc_power_always_on();
|
||||
adc_gpio_init(adc_unit, channel);
|
||||
adc_set_i2s_data_len(adc_unit, table_len);
|
||||
adc_set_i2s_data_pattern(adc_unit, 0, channel, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11);
|
||||
@@ -1246,12 +1255,55 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc1_i2s_mode_acquire()
|
||||
{
|
||||
//lazy initialization
|
||||
//for i2s, block until acquire the lock
|
||||
_lock_acquire( &adc1_i2s_lock );
|
||||
ESP_LOGD( RTC_MODULE_TAG, "i2s mode takes adc1 lock." );
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU;
|
||||
//switch SARADC into DIG channel
|
||||
SENS.sar_read_ctrl.sar1_dig_force = 1;
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc1_adc_mode_acquire()
|
||||
{
|
||||
//lazy initialization
|
||||
//for adc1, block until acquire the lock
|
||||
_lock_acquire( &adc1_i2s_lock );
|
||||
ESP_LOGD( RTC_MODULE_TAG, "adc mode takes adc1 lock." );
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
// for now the WiFi would use ADC2 and set xpd_sar force on.
|
||||
// so we can not reset xpd_sar to fsm mode directly.
|
||||
// We should handle this after the synchronization mechanism is established.
|
||||
|
||||
//switch SARADC into RTC channel
|
||||
SENS.sar_read_ctrl.sar1_dig_force = 0;
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc1_lock_release()
|
||||
{
|
||||
RTC_MODULE_CHECK((uint32_t*)adc1_i2s_lock != NULL, "adc1 lock release called before acquire", ESP_ERR_INVALID_STATE );
|
||||
// for now the WiFi would use ADC2 and set xpd_sar force on.
|
||||
// so we can not reset xpd_sar to fsm mode directly.
|
||||
// We should handle this after the synchronization mechanism is established.
|
||||
|
||||
_lock_release( &adc1_i2s_lock );
|
||||
ESP_LOGD( RTC_MODULE_TAG, "returns adc1 lock." );
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int adc1_get_raw(adc1_channel_t channel)
|
||||
{
|
||||
uint16_t adc_value;
|
||||
RTC_MODULE_CHECK(channel < ADC1_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG);
|
||||
|
||||
adc_power_on();
|
||||
adc1_adc_mode_acquire();
|
||||
adc_power_on();
|
||||
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
//Adc Controler is Rtc module,not ulp coprocessor
|
||||
@@ -1274,6 +1326,7 @@ int adc1_get_raw(adc1_channel_t channel)
|
||||
while (SENS.sar_meas_start1.meas1_done_sar == 0);
|
||||
adc_value = SENS.sar_meas_start1.meas1_data_sar;
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
adc1_lock_release();
|
||||
return adc_value;
|
||||
}
|
||||
|
||||
@@ -1467,6 +1520,8 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
|
||||
rtc_gpio_input_disable(gpio);
|
||||
rtc_gpio_pullup_dis(gpio);
|
||||
rtc_gpio_pulldown_dis(gpio);
|
||||
//force fsm
|
||||
adc_power_always_on(); //Select power source of ADC
|
||||
|
||||
RTCCNTL.bias_conf.dbg_atten = 0; //Check DBG effect outside sleep mode
|
||||
//set dtest (MUX_SEL : 0 -> RTC; 1-> vdd_sar2)
|
||||
@@ -1475,8 +1530,6 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
|
||||
RTCCNTL.test_mux.ent_rtc = 1;
|
||||
//set sar2_en_test
|
||||
SENS.sar_start_force.sar2_en_test = 1;
|
||||
//force fsm
|
||||
SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_ENABLE; //Select power source of ADC
|
||||
//set sar2 en force
|
||||
SENS.sar_meas_start2.sar2_en_pad_force = 1; //Pad bitmap controlled by SW
|
||||
//set en_pad for channels 7,8,9 (bits 0x380)
|
||||
|
||||
@@ -344,7 +344,7 @@ void spicommon_cs_free(spi_host_device_t host, int cs_io_num)
|
||||
}
|
||||
|
||||
//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to.
|
||||
void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
|
||||
void IRAM_ATTR spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
|
||||
{
|
||||
int n = 0;
|
||||
while (len) {
|
||||
|
||||
@@ -43,6 +43,8 @@ static const char* UART_TAG = "uart";
|
||||
#define UART_EMPTY_THRESH_DEFAULT (10)
|
||||
#define UART_FULL_THRESH_DEFAULT (120)
|
||||
#define UART_TOUT_THRESH_DEFAULT (10)
|
||||
#define UART_CLKDIV_FRAG_BIT_WIDTH (3)
|
||||
#define UART_TOUT_REF_FACTOR_DEFAULT (UART_CLK_FREQ/(REF_CLK_FREQ<<UART_CLKDIV_FRAG_BIT_WIDTH))
|
||||
#define UART_TX_IDLE_NUM_DEFAULT (0)
|
||||
#define UART_PATTERN_DET_QLEN_DEFAULT (10)
|
||||
|
||||
@@ -654,7 +656,13 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
UART[uart_num]->int_clr.val = UART_INTR_MASK;
|
||||
if(intr_conf->intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M) {
|
||||
UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);
|
||||
//Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times.
|
||||
//T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH)
|
||||
if(UART[uart_num]->conf0.tick_ref_always_on == 0) {
|
||||
UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT) & UART_RX_TOUT_THRHD_V);
|
||||
} else {
|
||||
UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);
|
||||
}
|
||||
UART[uart_num]->conf1.rx_tout_en = 1;
|
||||
} else {
|
||||
UART[uart_num]->conf1.rx_tout_en = 0;
|
||||
@@ -1132,8 +1140,8 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
|
||||
if(res == pdTRUE) {
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len;
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
p_uart_obj[uart_num]->rx_buffer_full_flg = false;
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);
|
||||
}
|
||||
}
|
||||
@@ -1178,6 +1186,14 @@ esp_err_t uart_flush_input(uart_port_t uart_num)
|
||||
}
|
||||
data = (uint8_t*) xRingbufferReceive(p_uart->rx_ring_buf, &size, (portTickType) 0);
|
||||
if(data == NULL) {
|
||||
if( p_uart_obj[uart_num]->rx_buffered_len != 0 ) {
|
||||
ESP_LOGE(UART_TAG, "rx_buffered_len error");
|
||||
p_uart_obj[uart_num]->rx_buffered_len = 0;
|
||||
}
|
||||
//We also need to clear the `rx_buffer_full_flg` here.
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
p_uart_obj[uart_num]->rx_buffer_full_flg = false;
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
break;
|
||||
}
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
@@ -1190,8 +1206,8 @@ esp_err_t uart_flush_input(uart_port_t uart_num)
|
||||
if(res == pdTRUE) {
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len;
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
p_uart_obj[uart_num]->rx_buffer_full_flg = false;
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,3 +38,7 @@ CFLAGS+=-mfix-esp32-psram-cache-issue
|
||||
CXXFLAGS+=-mfix-esp32-psram-cache-issue
|
||||
endif
|
||||
|
||||
# Enable dynamic esp_timer overflow value if building unit tests
|
||||
ifneq ("$(TEST_COMPONENTS_LIST)","")
|
||||
CPPFLAGS += -DESP_TIMER_DYNAMIC_OVERFLOW_VAL
|
||||
endif
|
||||
|
||||
@@ -44,7 +44,7 @@ static volatile uint32_t reason[ portNUM_PROCESSORS ];
|
||||
ToDo: There is a small chance the CPU already has yielded when this ISR is serviced. In that case, it's running the intended task but
|
||||
the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably just schedule the task again, but have to check that.
|
||||
*/
|
||||
static void esp_crosscore_isr_handle_yield()
|
||||
static inline void IRAM_ATTR esp_crosscore_isr_handle_yield()
|
||||
{
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
@@ -82,7 +82,18 @@
|
||||
* ISR happens follow set_alarm, so change the ALARM_OVERFLOW_VAL to resolve this problem.
|
||||
* Set it to 0xefffffffUL. The remain 0x10000000UL(about 3 second) is enough to handle ISR.
|
||||
*/
|
||||
#define ALARM_OVERFLOW_VAL 0xefffffffUL
|
||||
#define DEFAULT_ALARM_OVERFLOW_VAL 0xefffffffUL
|
||||
|
||||
/* Provision to set lower overflow value for unit testing. Lowering the
|
||||
* overflow value helps check for race conditions which occur near overflow
|
||||
* moment.
|
||||
*/
|
||||
#ifndef ESP_TIMER_DYNAMIC_OVERFLOW_VAL
|
||||
#define ALARM_OVERFLOW_VAL DEFAULT_ALARM_OVERFLOW_VAL
|
||||
#else
|
||||
static uint32_t s_alarm_overflow_val = DEFAULT_ALARM_OVERFLOW_VAL;
|
||||
#define ALARM_OVERFLOW_VAL (s_alarm_overflow_val)
|
||||
#endif
|
||||
|
||||
static const char* TAG = "esp_timer_impl";
|
||||
|
||||
@@ -206,18 +217,6 @@ void IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp)
|
||||
// Adjust current time if overflow has happened
|
||||
bool overflow = timer_overflow_happened();
|
||||
uint64_t cur_count = REG_READ(FRC_TIMER_COUNT_REG(1));
|
||||
uint32_t offset = s_timer_ticks_per_us * 2; //remain 2us for more safe
|
||||
|
||||
//If overflow is going to happen in 1us, let's wait until it happens,
|
||||
//else we think it will not happen before new alarm set.
|
||||
//And we should wait current timer count less than ALARM_OVERFLOW_VAL,
|
||||
//maybe equals to 0.
|
||||
if (cur_count + offset >= ALARM_OVERFLOW_VAL) {
|
||||
do {
|
||||
overflow = timer_overflow_happened();
|
||||
cur_count = REG_READ(FRC_TIMER_COUNT_REG(1));
|
||||
} while(!overflow || cur_count == ALARM_OVERFLOW_VAL);
|
||||
}
|
||||
|
||||
if (overflow) {
|
||||
assert(time_after_timebase_us > s_timer_us_per_overflow);
|
||||
@@ -227,13 +226,17 @@ void IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp)
|
||||
// Calculate desired timer compare value (may exceed 2^32-1)
|
||||
uint64_t compare_val = time_after_timebase_us * s_timer_ticks_per_us;
|
||||
uint32_t alarm_reg_val = ALARM_OVERFLOW_VAL;
|
||||
// Use calculated alarm value if it is less than 2^32-1
|
||||
// Use calculated alarm value if it is less than ALARM_OVERFLOW_VAL.
|
||||
// Note that if by the time we update ALARM_REG, COUNT_REG value is higher,
|
||||
// interrupt will not happen for another ALARM_OVERFLOW_VAL timer ticks,
|
||||
// so need to check if alarm value is too close in the future (e.g. <2 us away).
|
||||
const uint32_t offset = s_timer_ticks_per_us * 2;
|
||||
if (compare_val < ALARM_OVERFLOW_VAL) {
|
||||
// If we by the time we update ALARM_REG, COUNT_REG value is higher,
|
||||
// interrupt will not happen for another 2^32 timer ticks, so need to
|
||||
// check if alarm value is too close in the future (e.g. <1 us away).
|
||||
if (compare_val < cur_count + offset) {
|
||||
compare_val = cur_count + offset;
|
||||
if (compare_val > ALARM_OVERFLOW_VAL) {
|
||||
compare_val = ALARM_OVERFLOW_VAL;
|
||||
}
|
||||
}
|
||||
alarm_reg_val = (uint32_t) compare_val;
|
||||
}
|
||||
@@ -361,3 +364,17 @@ uint64_t IRAM_ATTR esp_timer_impl_get_min_period_us()
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
#ifdef ESP_TIMER_DYNAMIC_OVERFLOW_VAL
|
||||
uint32_t esp_timer_impl_get_overflow_val()
|
||||
{
|
||||
return s_alarm_overflow_val;
|
||||
}
|
||||
|
||||
void esp_timer_impl_set_overflow_val(uint32_t overflow_val)
|
||||
{
|
||||
s_alarm_overflow_val = overflow_val;
|
||||
/* update alarm value */
|
||||
esp_timer_impl_update_apb_freq(esp_clk_apb_freq() / 1000000);
|
||||
}
|
||||
#endif // ESP_TIMER_DYNAMIC_OVERFLOW_VAL
|
||||
|
||||
@@ -290,7 +290,13 @@ esp_err_t esp_wifi_restore(void);
|
||||
*
|
||||
* @attention 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode
|
||||
* @attention 2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect.
|
||||
*
|
||||
* @attention 3. The scanning triggered by esp_wifi_start_scan() will not be effective until connection between ESP32 and the AP is established.
|
||||
* If ESP32 is scanning and connecting at the same time, ESP32 will abort scanning and return a warning message and error
|
||||
* number ESP_ERR_WIFI_STATE.
|
||||
* If you want to do reconnection after ESP32 received disconnect event, remember to add the maximum retry time, otherwise the called
|
||||
* scan will not work. This is especially true when the AP doesn't exist, and you still try reconnection after ESP32 received disconnect
|
||||
* event with the reason code WIFI_REASON_NO_AP_FOUND.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
|
||||
@@ -353,6 +359,7 @@ esp_err_t esp_wifi_deauth_sta(uint16_t aid);
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start
|
||||
* - ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout
|
||||
* - ESP_ERR_WIFI_STATE: wifi still connecting when invoke esp_wifi_scan_start
|
||||
* - others: refer to error code in esp_err.h
|
||||
*/
|
||||
esp_err_t esp_wifi_scan_start(const wifi_scan_config_t *config, bool block);
|
||||
|
||||
@@ -89,7 +89,6 @@ SECTIONS
|
||||
*libesp32.a:core_dump.o(.literal .text .literal.* .text.*)
|
||||
*libapp_trace.a:(.literal .text .literal.* .text.*)
|
||||
*libxtensa-debug-module.a:eri.o(.literal .text .literal.* .text.*)
|
||||
*libphy.a:(.literal .text .literal.* .text.*)
|
||||
*librtc.a:(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:(.literal .text .literal.* .text.*)
|
||||
*libhal.a:(.literal .text .literal.* .text.*)
|
||||
|
||||
Submodule components/esp32/lib updated: a472a0ce53...e923fea4e8
@@ -241,19 +241,34 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle,
|
||||
const esp_phy_calibration_data_t* cal_data)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16));
|
||||
ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version);
|
||||
err = nvs_set_u32(handle, PHY_CAL_VERSION_KEY, cal_format_version);
|
||||
|
||||
err = nvs_set_blob(handle, PHY_CAL_DATA_KEY, cal_data, sizeof(*cal_data));
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: store calibration data failed(0x%x)\n", __func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
uint8_t sta_mac[6];
|
||||
esp_efuse_mac_get_default(sta_mac);
|
||||
err = nvs_set_blob(handle, PHY_CAL_MAC_KEY, sta_mac, sizeof(sta_mac));
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: store calibration mac failed(0x%x)\n", __func__, err);
|
||||
return err;
|
||||
}
|
||||
err = nvs_set_blob(handle, PHY_CAL_DATA_KEY, cal_data, sizeof(*cal_data));
|
||||
|
||||
uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16));
|
||||
ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version);
|
||||
err = nvs_set_u32(handle, PHY_CAL_VERSION_KEY, cal_format_version);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: store calibration version failed(0x%x)\n", __func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = nvs_commit(handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: store calibration nvs commit failed(0x%x)\n", __func__, err);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/param.h>
|
||||
#include "unity.h"
|
||||
#include "esp_timer.h"
|
||||
#include "../esp_timer_impl.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -14,6 +16,20 @@
|
||||
#define WITH_PROFILING 1
|
||||
#endif
|
||||
|
||||
extern uint32_t esp_timer_impl_get_overflow_val();
|
||||
extern void esp_timer_impl_set_overflow_val(uint32_t overflow_val);
|
||||
|
||||
static uint32_t s_old_overflow_val;
|
||||
|
||||
static void setup_overflow()
|
||||
{
|
||||
s_old_overflow_val = esp_timer_impl_get_overflow_val();
|
||||
esp_timer_impl_set_overflow_val(0x7fffff); /* overflow every ~0.1 sec */}
|
||||
|
||||
static void teardown_overflow()
|
||||
{
|
||||
esp_timer_impl_set_overflow_val(s_old_overflow_val);
|
||||
}
|
||||
|
||||
TEST_CASE("esp_timer orders timers correctly", "[esp_timer]")
|
||||
{
|
||||
@@ -26,6 +42,7 @@ TEST_CASE("esp_timer orders timers correctly", "[esp_timer]")
|
||||
const size_t num_timers = sizeof(timeouts)/sizeof(timeouts[0]);
|
||||
esp_timer_handle_t handles[num_timers];
|
||||
char* names[num_timers];
|
||||
setup_overflow();
|
||||
for (size_t i = 0; i < num_timers; ++i) {
|
||||
asprintf(&names[i], "timer%d", i);
|
||||
esp_timer_create_args_t args = {
|
||||
@@ -35,6 +52,7 @@ TEST_CASE("esp_timer orders timers correctly", "[esp_timer]")
|
||||
TEST_ESP_OK(esp_timer_create(&args, &handles[i]));
|
||||
TEST_ESP_OK(esp_timer_start_once(handles[i], timeouts[i] * 100));
|
||||
}
|
||||
teardown_overflow();
|
||||
char* stream_str[1024];
|
||||
FILE* stream = fmemopen(stream_str, sizeof(stream_str), "r+");
|
||||
TEST_ESP_OK(esp_timer_dump(stream));
|
||||
@@ -67,6 +85,42 @@ TEST_CASE("esp_timer orders timers correctly", "[esp_timer]")
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
TEST_CASE("esp_timer_impl_set_alarm stress test", "[esp_timer]")
|
||||
{
|
||||
const int test_time_sec = 10;
|
||||
|
||||
void set_alarm_task(void* arg)
|
||||
{
|
||||
SemaphoreHandle_t done = (SemaphoreHandle_t) arg;
|
||||
|
||||
uint64_t start = esp_timer_impl_get_time();
|
||||
uint64_t now = start;
|
||||
int count = 0;
|
||||
const int delays[] = {50, 5000, 10000000};
|
||||
const int delays_count = sizeof(delays)/sizeof(delays[0]);
|
||||
while (now - start < test_time_sec * 1000000) {
|
||||
now = esp_timer_impl_get_time();
|
||||
esp_timer_impl_set_alarm(now + delays[count % delays_count]);
|
||||
++count;
|
||||
}
|
||||
xSemaphoreGive(done);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
SemaphoreHandle_t done = xSemaphoreCreateCounting(portNUM_PROCESSORS, 0);
|
||||
setup_overflow();
|
||||
xTaskCreatePinnedToCore(&set_alarm_task, "set_alarm_0", 4096, done, UNITY_FREERTOS_PRIORITY, NULL, 0);
|
||||
#if portNUM_PROCESSORS == 2
|
||||
xTaskCreatePinnedToCore(&set_alarm_task, "set_alarm_1", 4096, done, UNITY_FREERTOS_PRIORITY, NULL, 1);
|
||||
#endif
|
||||
|
||||
TEST_ASSERT(xSemaphoreTake(done, test_time_sec * 2 * 1000 / portTICK_PERIOD_MS));
|
||||
#if portNUM_PROCESSORS == 2
|
||||
TEST_ASSERT(xSemaphoreTake(done, test_time_sec * 2 * 1000 / portTICK_PERIOD_MS));
|
||||
#endif
|
||||
teardown_overflow();
|
||||
vSemaphoreDelete(done);
|
||||
}
|
||||
|
||||
TEST_CASE("esp_timer produces correct delay", "[esp_timer]")
|
||||
{
|
||||
@@ -89,6 +143,7 @@ TEST_CASE("esp_timer produces correct delay", "[esp_timer]")
|
||||
const size_t delays_count = sizeof(delays_ms)/sizeof(delays_ms[0]);
|
||||
|
||||
ref_clock_init();
|
||||
setup_overflow();
|
||||
for (size_t i = 0; i < delays_count; ++i) {
|
||||
t_end = 0;
|
||||
int64_t t_start = ref_clock_get();
|
||||
@@ -102,6 +157,7 @@ TEST_CASE("esp_timer produces correct delay", "[esp_timer]")
|
||||
|
||||
TEST_ASSERT_INT32_WITHIN(portTICK_PERIOD_MS, delays_ms[i], ms_diff);
|
||||
}
|
||||
teardown_overflow();
|
||||
ref_clock_deinit();
|
||||
|
||||
TEST_ESP_OK( esp_timer_dump(stdout) );
|
||||
@@ -149,6 +205,7 @@ TEST_CASE("periodic esp_timer produces correct delays", "[esp_timer]")
|
||||
};
|
||||
TEST_ESP_OK(esp_timer_create(&create_args, &timer1));
|
||||
ref_clock_init();
|
||||
setup_overflow();
|
||||
args.timer = timer1;
|
||||
args.t_start = ref_clock_get();
|
||||
args.done = xSemaphoreCreateBinary();
|
||||
@@ -160,6 +217,7 @@ TEST_CASE("periodic esp_timer produces correct delays", "[esp_timer]")
|
||||
for (size_t i = 0; i < NUM_INTERVALS; ++i) {
|
||||
TEST_ASSERT_INT32_WITHIN(portTICK_PERIOD_MS, (i + 1) * delay_ms, args.intervals[i]);
|
||||
}
|
||||
teardown_overflow();
|
||||
ref_clock_deinit();
|
||||
TEST_ESP_OK( esp_timer_dump(stdout) );
|
||||
|
||||
@@ -316,6 +374,7 @@ TEST_CASE("esp_timer for very short intervals", "[esp_timer]")
|
||||
esp_timer_handle_t timer1, timer2;
|
||||
ESP_ERROR_CHECK( esp_timer_create(&timer_args, &timer1) );
|
||||
ESP_ERROR_CHECK( esp_timer_create(&timer_args, &timer2) );
|
||||
setup_overflow();
|
||||
const int timeout_ms = 10;
|
||||
for (int timeout_delta_us = -150; timeout_delta_us < 150; timeout_delta_us++) {
|
||||
printf("delta=%d", timeout_delta_us);
|
||||
@@ -328,6 +387,7 @@ TEST_CASE("esp_timer for very short intervals", "[esp_timer]")
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_timer_stop(timer2));
|
||||
}
|
||||
|
||||
teardown_overflow();
|
||||
vSemaphoreDelete(semaphore);
|
||||
}
|
||||
|
||||
@@ -344,40 +404,75 @@ TEST_CASE("esp_timer_get_time call takes less than 1us", "[esp_timer]")
|
||||
TEST_PERFORMANCE_LESS_THAN(ESP_TIMER_GET_TIME_PER_CALL, "%dns", ns_per_call);
|
||||
}
|
||||
|
||||
/* This test runs for about 10 minutes and is disabled in CI.
|
||||
* Such run time is needed to have FRC2 timer overflow a few times.
|
||||
*/
|
||||
TEST_CASE("esp_timer_get_time returns monotonic values", "[esp_timer][ignore]")
|
||||
TEST_CASE("esp_timer_get_time returns monotonic values", "[esp_timer]")
|
||||
{
|
||||
void timer_test_task(void* arg) {
|
||||
int64_t delta = esp_timer_get_time() - ref_clock_get();
|
||||
typedef struct {
|
||||
SemaphoreHandle_t done;
|
||||
bool pass;
|
||||
int test_cnt;
|
||||
int error_cnt;
|
||||
int64_t total_sq_error;
|
||||
int64_t max_error;
|
||||
} test_state_t;
|
||||
|
||||
const int iter_count = 1000000000;
|
||||
for (int i = 0; i < iter_count; ++i) {
|
||||
int64_t now = esp_timer_get_time();
|
||||
int64_t ref_now = ref_clock_get();
|
||||
int64_t diff = now - (ref_now + delta);
|
||||
void timer_test_task(void* arg) {
|
||||
test_state_t* state = (test_state_t*) arg;
|
||||
state->pass = true;
|
||||
int64_t start_time = ref_clock_get();
|
||||
int64_t delta = esp_timer_get_time() - start_time;
|
||||
|
||||
int64_t now = start_time;
|
||||
int error_repeat_cnt = 0;
|
||||
while (now - start_time < 10000000) { /* 10 seconds */
|
||||
int64_t hs_now = esp_timer_get_time();
|
||||
now = ref_clock_get();
|
||||
int64_t diff = hs_now - (now + delta);
|
||||
/* Allow some difference due to rtos tick interrupting task between
|
||||
* getting 'now' and 'ref_now'.
|
||||
*/
|
||||
TEST_ASSERT_INT32_WITHIN(100, 0, (int) diff);
|
||||
if (abs(diff) > 100) {
|
||||
error_repeat_cnt++;
|
||||
state->error_cnt++;
|
||||
} else {
|
||||
error_repeat_cnt = 0;
|
||||
}
|
||||
if (error_repeat_cnt > 2) {
|
||||
printf("diff=%lld\n", diff);
|
||||
state->pass = false;
|
||||
}
|
||||
state->max_error = MAX(state->max_error, abs(diff));
|
||||
state->test_cnt++;
|
||||
state->total_sq_error += diff * diff;
|
||||
}
|
||||
|
||||
xSemaphoreGive((SemaphoreHandle_t) arg);
|
||||
xSemaphoreGive(state->done);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
ref_clock_init();
|
||||
SemaphoreHandle_t done_1 = xSemaphoreCreateBinary();
|
||||
SemaphoreHandle_t done_2 = xSemaphoreCreateBinary();
|
||||
setup_overflow();
|
||||
|
||||
xTaskCreatePinnedToCore(&timer_test_task, "t1", 4096, (void*) done_1, 6, NULL, 0);
|
||||
xTaskCreatePinnedToCore(&timer_test_task, "t2", 4096, (void*) done_2, 6, NULL, 1);
|
||||
test_state_t states[portNUM_PROCESSORS] = {0};
|
||||
SemaphoreHandle_t done = xSemaphoreCreateCounting(portNUM_PROCESSORS, 0);
|
||||
for (int i = 0; i < portNUM_PROCESSORS; ++i) {
|
||||
states[i].done = done;
|
||||
xTaskCreatePinnedToCore(&timer_test_task, "test", 4096, &states[i], 6, NULL, i);
|
||||
}
|
||||
|
||||
TEST_ASSERT_TRUE( xSemaphoreTake(done_1, portMAX_DELAY) );
|
||||
TEST_ASSERT_TRUE( xSemaphoreTake(done_2, portMAX_DELAY) );
|
||||
vSemaphoreDelete(done_1);
|
||||
vSemaphoreDelete(done_2);
|
||||
for (int i = 0; i < portNUM_PROCESSORS; ++i) {
|
||||
TEST_ASSERT_TRUE( xSemaphoreTake(done, portMAX_DELAY) );
|
||||
printf("CPU%d: %s test_cnt=%d error_cnt=%d std_error=%d |max_error|=%d\n",
|
||||
i, states[i].pass ? "PASS" : "FAIL",
|
||||
states[i].test_cnt, states[i].error_cnt,
|
||||
(int) sqrt(states[i].total_sq_error / states[i].test_cnt), (int) states[i].max_error);
|
||||
}
|
||||
|
||||
vSemaphoreDelete(done);
|
||||
teardown_overflow();
|
||||
ref_clock_deinit();
|
||||
|
||||
for (int i = 0; i < portNUM_PROCESSORS; ++i) {
|
||||
TEST_ASSERT(states[i].pass);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Can dump esp_timer stats", "[esp_timer]")
|
||||
|
||||
@@ -2458,8 +2458,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
//ToDo: figure out locking
|
||||
// taskENTER_CRITICAL(&pxQueue->mux);
|
||||
taskENTER_CRITICAL(&(((Queue_t * )xQueueOrSemaphore)->mux));
|
||||
{
|
||||
if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL )
|
||||
{
|
||||
@@ -2478,7 +2477,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
}
|
||||
// taskEXIT_CRITICAL(&pxQueue->mux);
|
||||
taskEXIT_CRITICAL(&(((Queue_t * )xQueueOrSemaphore)->mux));
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
@@ -2507,12 +2506,12 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// taskENTER_CRITICAL(&pxQueue->mux);
|
||||
taskENTER_CRITICAL(&(pxQueueOrSemaphore->mux));
|
||||
{
|
||||
/* The queue is no longer contained in the set. */
|
||||
pxQueueOrSemaphore->pxQueueSetContainer = NULL;
|
||||
}
|
||||
// taskEXIT_CRITICAL(&pxQueue->mux);
|
||||
taskEXIT_CRITICAL(&(pxQueueOrSemaphore->mux));
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
|
||||
@@ -2555,9 +2554,15 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
Queue_t *pxQueueSetContainer = pxQueue->pxQueueSetContainer;
|
||||
BaseType_t xReturn = pdFALSE;
|
||||
|
||||
/* This function must be called form a critical section. */
|
||||
/*
|
||||
* This function is called with a Queue's / Semaphore's spinlock already
|
||||
* acquired. Acquiring the Queue set's spinlock is still necessary.
|
||||
*/
|
||||
|
||||
configASSERT( pxQueueSetContainer );
|
||||
|
||||
//Acquire the Queue set's spinlock
|
||||
portENTER_CRITICAL(&(pxQueueSetContainer->mux));
|
||||
configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength );
|
||||
|
||||
if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength )
|
||||
@@ -2588,6 +2593,9 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
//Release the Queue set's spinlock
|
||||
portEXIT_CRITICAL(&(pxQueueSetContainer->mux));
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
137
components/freertos/test/test_queuesets.c
Normal file
137
components/freertos/test/test_queuesets.c
Normal file
@@ -0,0 +1,137 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
|
||||
/*
|
||||
* Basic queue set tests. Multiple queues are added to a queue set then each
|
||||
* queue is filled in a sequential order. The members returned from the queue
|
||||
* set must adhered to the order in which the queues were filled.
|
||||
*/
|
||||
#define NO_OF_QUEUES 5
|
||||
#define QUEUE_LEN 4
|
||||
#define ITEM_SIZE sizeof(uint32_t)
|
||||
|
||||
static QueueHandle_t handles[NO_OF_QUEUES];
|
||||
static QueueSetHandle_t set_handle;
|
||||
|
||||
TEST_CASE("Test Queue sets", "[freertos]")
|
||||
{
|
||||
//Create queue set, queues, and add queues to queue set
|
||||
set_handle = xQueueCreateSet(NO_OF_QUEUES * QUEUE_LEN);
|
||||
for (int i = 0; i < NO_OF_QUEUES; i++) {
|
||||
handles[i] = xQueueCreate(QUEUE_LEN, ITEM_SIZE);
|
||||
TEST_ASSERT_MESSAGE(handles[i] != NULL, "Failed to create queue");
|
||||
TEST_ASSERT_MESSAGE(xQueueAddToSet(handles[i], set_handle) == pdPASS, "Failed to add to queue set");
|
||||
}
|
||||
|
||||
//Fill queue set via filling each queue
|
||||
for (int i = 0; i < NO_OF_QUEUES; i++) {
|
||||
for (int j = 0; j < QUEUE_LEN; j++) {
|
||||
uint32_t item_num = (i * QUEUE_LEN) + j;
|
||||
TEST_ASSERT_MESSAGE(xQueueSendToBack(handles[i], &item_num, portMAX_DELAY) == pdTRUE, "Failed to send to queue");
|
||||
}
|
||||
}
|
||||
|
||||
//Check queue set is notified in correct order
|
||||
for (int i = 0; i < NO_OF_QUEUES; i++) {
|
||||
for (int j = 0; j < QUEUE_LEN; j++) {
|
||||
QueueSetMemberHandle_t member = xQueueSelectFromSet(set_handle, portMAX_DELAY);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(handles[i], member, "Incorrect queue set member returned");
|
||||
uint32_t item;
|
||||
xQueueReceive((QueueHandle_t)member, &item, 0);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(((i * QUEUE_LEN) + j), item, "Incorrect item value");
|
||||
}
|
||||
}
|
||||
|
||||
//Remove queues from queue set and delete queues
|
||||
for (int i = 0; i < NO_OF_QUEUES; i++) {
|
||||
TEST_ASSERT_MESSAGE(xQueueRemoveFromSet(handles[i], set_handle), "Failed to remove from queue set");
|
||||
vQueueDelete(handles[i]);
|
||||
}
|
||||
vQueueDelete(set_handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Queue set thread safety test. Test the SMP thread safety by adding two queues
|
||||
* to a queue set and have a task on each core send to the queues simultaneously.
|
||||
* Check returned queue set members are valid.
|
||||
*/
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
static volatile bool sync_flags[portNUM_PROCESSORS];
|
||||
static SemaphoreHandle_t sync_sem;
|
||||
|
||||
static void send_task(void *arg)
|
||||
{
|
||||
QueueHandle_t queue = (QueueHandle_t)arg;
|
||||
|
||||
//Wait until task on the other core starts running
|
||||
xSemaphoreTake(sync_sem, portMAX_DELAY);
|
||||
sync_flags[xPortGetCoreID()] = true;
|
||||
while (!sync_flags[!xPortGetCoreID()]) {
|
||||
;
|
||||
}
|
||||
|
||||
//Fill queue
|
||||
for (int i = 0; i < QUEUE_LEN; i++) {
|
||||
uint32_t item = i;
|
||||
xQueueSendToBack(queue, &item, portMAX_DELAY);
|
||||
}
|
||||
|
||||
xSemaphoreGive(sync_sem);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test Queue sets thread safety", "[freertos]")
|
||||
{
|
||||
//Create queue set, queues, and a send task on each core
|
||||
sync_sem = xSemaphoreCreateCounting(portNUM_PROCESSORS, 0);
|
||||
QueueHandle_t queue_handles[portNUM_PROCESSORS];
|
||||
QueueSetHandle_t queueset_handle = xQueueCreateSet(portNUM_PROCESSORS * QUEUE_LEN);
|
||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
sync_flags[i] = false;
|
||||
queue_handles[i] = xQueueCreate(QUEUE_LEN, ITEM_SIZE);
|
||||
TEST_ASSERT_MESSAGE(xQueueAddToSet(queue_handles[i], queueset_handle) == pdPASS, "Failed to add to queue set");
|
||||
xTaskCreatePinnedToCore(send_task, "send", 2048, (void *)queue_handles[i], 10, NULL, i);
|
||||
}
|
||||
|
||||
//Start both send tasks
|
||||
portDISABLE_INTERRUPTS();
|
||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
xSemaphoreGive(sync_sem);
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
vTaskDelay(2);
|
||||
|
||||
//Check returned queue set members are valid
|
||||
uint32_t expect_0 = 0;
|
||||
uint32_t expect_1 = 0;
|
||||
for (int i = 0; i < (portNUM_PROCESSORS * QUEUE_LEN); i++) {
|
||||
QueueSetMemberHandle_t member = xQueueSelectFromSet(queueset_handle, portMAX_DELAY);
|
||||
uint32_t item;
|
||||
if (member == queue_handles[0]) {
|
||||
xQueueReceive((QueueHandle_t)member, &item, 0);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(expect_0, item, "Incorrect item value");
|
||||
expect_0++;
|
||||
} else if (member == queue_handles[1]) {
|
||||
xQueueReceive((QueueHandle_t)member, &item, 0);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(expect_1, item, "Incorrect item value");
|
||||
expect_1++;
|
||||
} else {
|
||||
TEST_ASSERT_MESSAGE(0, "Incorrect queue set member returned");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
xSemaphoreTake(sync_sem, portMAX_DELAY);
|
||||
}
|
||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
xQueueRemoveFromSet(queueset_handle, handles[i]);
|
||||
vQueueDelete(queue_handles[i]);
|
||||
}
|
||||
vQueueDelete(queueset_handle);
|
||||
}
|
||||
#endif
|
||||
@@ -798,7 +798,7 @@ test cases:
|
||||
- ['R PC_COM C +NIC_START:OK']
|
||||
- - "SSC SSC1 bleadv -D -z stop"
|
||||
- ["R SSC1 C +BLEADV"]
|
||||
- - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['NPDU','PDU']"
|
||||
- - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['PDU','PDU']"
|
||||
- [""]
|
||||
- - "SSC SSC1 bleadv -D -z start -t 2 -i {%s}"
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
@@ -842,7 +842,7 @@ test cases:
|
||||
- ['R PC_COM C +NIC_START:OK']
|
||||
- - "SSC SSC1 bleadv -D -z stop"
|
||||
- ["R SSC1 C +BLEADV"]
|
||||
- - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['NPDU','PDU']"
|
||||
- - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['PDU','PDU']"
|
||||
- [""]
|
||||
- - "SSC SSC1 bleadv -D -z start -t 3 -i {%s}"
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
@@ -890,7 +890,7 @@ test cases:
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
- - "SSC SSC2 bleadv -D -z stop"
|
||||
- ["R SSC2 C +BLEADV:OK"]
|
||||
- - "SSC SSC2 blescan -L -c 0 -s 0"
|
||||
- - "SSC SSC2 blescan -L -c 0 -s 0 -d 1"
|
||||
- ["R SSC2 C +BLESCAN:SetScanParam,OK"]
|
||||
- - "SSC SSC2 blescan -D -z start -t 3 -e 2"
|
||||
- - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x1011121314151617181910111213141516171819"%%(<dut1_bt_mac>)'
|
||||
@@ -944,7 +944,7 @@ test cases:
|
||||
- ["R SSC2 C +BLEADV:OK"]
|
||||
- - LOOP 4 2 "[0,1,2,3]"
|
||||
- ['']
|
||||
- - "SSC SSC2 blescan -L -c 0 -s 1 -o {%d}"
|
||||
- - "SSC SSC2 blescan -L -c 0 -s 1 -o {%d} -d 1"
|
||||
- ["R SSC2 C +BLESCAN:SetScanParam,OK"]
|
||||
- - "SSC SSC2 blescan -D -z start -t 1"
|
||||
- ['R SSC2 P <dut1_bt_mac> C Complete']
|
||||
@@ -1075,7 +1075,7 @@ test cases:
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
- - "SSC SSC1 bleadv -D -z start"
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
- - "SSC SSC2 blescan -L -c 0"
|
||||
- - "SSC SSC2 blescan -L -c 0 -d 1"
|
||||
- ["R SSC2 C +BLESCAN:SetScanParam,OK"]
|
||||
- - "SSC SSC2 blescan -D -z start -t 1"
|
||||
- ["R SSC2 P <dut1_bt_mac> C Complete"]
|
||||
@@ -1538,6 +1538,8 @@ test cases:
|
||||
- ""
|
||||
- - "SSC SSC1 bleadv -D -z stop"
|
||||
- ["R SSC1 C +BLEADV"]
|
||||
- - "SSC SSC2 blescan -L -c 0 -d 1"
|
||||
- ['R SSC2 C +BLESCAN']
|
||||
- - "SSC SSC1 bleadv -R -t 1 -r 0x020AEB06FF1112131415051220004000021901020106"
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
- - "SSC SSC1 bleadv -D -z start"
|
||||
@@ -1584,6 +1586,8 @@ test cases:
|
||||
- ["R SSC1 C +BLEADV"]
|
||||
- - "SSC SSC2 bleadv -D -z stop"
|
||||
- ["R SSC2 C +BLEADV:OK"]
|
||||
- - "SSC SSC2 blescan -L -c 0 -d 1"
|
||||
- ['R SSC2 C +BLESCAN']
|
||||
- - LOOP 4 3 "['0302ABCD','0303ABCD','0504ABCDABCD','0505ABCDABCD',]" "['insrv16,0xABCD','srv16,0xABCD','insrv32,0xABCDABCD','srv32,0xABCDABCD']"
|
||||
- - "SSC SSC1 bleadv -R -t 1 -r 0x{%s}"
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
@@ -1633,6 +1637,8 @@ test cases:
|
||||
- ["R SSC1 C +BLEADV"]
|
||||
- - "SSC SSC2 bleadv -D -z stop"
|
||||
- ["R SSC2 C +BLEADV:OK"]
|
||||
- - "SSC SSC2 blescan -L -c 0 -d 1"
|
||||
- ['R SSC2 C +BLESCAN']
|
||||
- - LOOP 3 3 "['0416ABCDEF','0620ABCDABCDEF','1221ABCDABCDABCDABCDABCDABCDABCDABCDEF',]" "['srvdata,0xABCDEF','srvdata32,0xABCDABCDEF','srvdata128,0xABCDABCDABCDABCDABCDABCDABCDABCDEF']"
|
||||
- - "SSC SSC1 bleadv -R -t 1 -r 0x{%s}"
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
@@ -1671,6 +1677,8 @@ test cases:
|
||||
- ""
|
||||
- - "SSC SSC1 bleadv -D -z stop"
|
||||
- ["R SSC1 C +BLEADV"]
|
||||
- - "SSC SSC2 blescan -L -c 0 -d 1"
|
||||
- ['R SSC2 C +BLESCAN']
|
||||
- - "SSC SSC1 bleadv -R -t 1 -r 0x15FF1011121314151617181910111213141516171819"
|
||||
- ["R SSC1 C +BLEADV:OK"]
|
||||
- - "SSC SSC1 bleadv -R -t 2 -r 0x020AEB051220004000021901020106"
|
||||
|
||||
@@ -83,7 +83,7 @@ config LWIP_STATS
|
||||
|
||||
config LWIP_ETHARP_TRUST_IP_MAC
|
||||
bool "Enable LWIP ARP trust"
|
||||
default y
|
||||
default n
|
||||
help
|
||||
Enabling this option allows ARP table to be updated.
|
||||
|
||||
@@ -96,6 +96,17 @@ config LWIP_ETHARP_TRUST_IP_MAC
|
||||
The peer *is* in the ARP table if it requested our address before.
|
||||
Also notice that this slows down input processing of every IP packet!
|
||||
|
||||
There are two known issues in real application if this feature is enabled:
|
||||
- The LAN peer may have bug to update the ARP table after the ARP entry is aged out.
|
||||
If the ARP entry on the LAN peer is aged out but failed to be updated, all IP packets
|
||||
sent from LWIP to the LAN peer will be dropped by LAN peer.
|
||||
- The LAN peer may not be trustful, the LAN peer may send IP packets to LWIP with
|
||||
two different MACs, but the same IP address. If this happens, the LWIP has problem
|
||||
to receive IP packets from LAN peer.
|
||||
|
||||
So the recommendation is to disable this option.
|
||||
Here the LAN peer means the other side to which the ESP station or soft-AP is connected.
|
||||
|
||||
config TCPIP_RECVMBOX_SIZE
|
||||
int "TCPIP task receive mail box size"
|
||||
default 32
|
||||
@@ -308,6 +319,16 @@ config TCP_QUEUE_OOSEQ
|
||||
Disable this option to save some RAM during TCP sessions, at the expense
|
||||
of increased retransmissions if segments arrive out of order.
|
||||
|
||||
config ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES
|
||||
bool "Keep TCP connections when IP changed"
|
||||
default n
|
||||
help
|
||||
This option is enabled when the following scenario happen:
|
||||
network dropped and reconnected, IP changes is like: 192.168.0.2->0.0.0.0->192.168.0.2
|
||||
|
||||
Disable this option to keep consistent with the original LWIP code behavior.
|
||||
|
||||
|
||||
choice TCP_OVERSIZE
|
||||
prompt "Pre-allocate transmit PBUF size"
|
||||
default TCP_OVERSIZE_MSS
|
||||
|
||||
@@ -407,9 +407,9 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
/* Let the stack know that we have accepted the connection. */
|
||||
API_MSG_VAR_ALLOC_DONTFAIL(msg);
|
||||
API_MSG_VAR_REF(msg).msg.conn = conn;
|
||||
/* don't care for the return value of lwip_netconn_do_recv */
|
||||
TCPIP_APIMSG_NOERR(&API_MSG_VAR_REF(msg), lwip_netconn_do_recv);
|
||||
API_MSG_VAR_REF(msg).msg.conn = newconn;
|
||||
/* don't care for the return value of lwip_netconn_do_accepted */
|
||||
TCPIP_APIMSG_NOERR(&API_MSG_VAR_REF(msg), lwip_netconn_do_accepted);
|
||||
API_MSG_VAR_FREE(msg);
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
|
||||
@@ -536,6 +536,9 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
to the application thread */
|
||||
newconn->last_err = err;
|
||||
|
||||
/* handle backlog counter */
|
||||
tcp_backlog_delayed(newpcb);
|
||||
|
||||
if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
|
||||
ESP_STATS_DROP_INC(esp.acceptmbox_post_fail);
|
||||
/* When returning != ERR_OK, the pcb is aborted in tcp_process(),
|
||||
@@ -1503,24 +1506,38 @@ lwip_netconn_do_recv(void *m)
|
||||
msg->err = ERR_OK;
|
||||
if (msg->conn->pcb.tcp != NULL) {
|
||||
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
if (msg->conn->pcb.tcp->state == LISTEN) {
|
||||
tcp_accepted(msg->conn->pcb.tcp);
|
||||
} else
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
{
|
||||
u32_t remaining = msg->msg.r.len;
|
||||
do {
|
||||
u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
|
||||
tcp_recved(msg->conn->pcb.tcp, recved);
|
||||
remaining -= recved;
|
||||
} while (remaining != 0);
|
||||
}
|
||||
u32_t remaining = msg->msg.r.len;
|
||||
do {
|
||||
u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
|
||||
tcp_recved(msg->conn->pcb.tcp, recved);
|
||||
remaining -= recved;
|
||||
} while (remaining != 0);
|
||||
}
|
||||
}
|
||||
TCPIP_APIMSG_ACK(msg);
|
||||
}
|
||||
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
/** Indicate that a TCP pcb has been accepted
|
||||
* Called from netconn_accept
|
||||
*
|
||||
* @param m the api_msg pointing to the connection
|
||||
*/
|
||||
void
|
||||
lwip_netconn_do_accepted(void *m)
|
||||
{
|
||||
struct api_msg_msg *msg = (struct api_msg_msg *)m;
|
||||
|
||||
msg->err = ERR_OK;
|
||||
if (msg->conn->pcb.tcp != NULL) {
|
||||
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
|
||||
tcp_backlog_accepted(msg->conn->pcb.tcp);
|
||||
}
|
||||
}
|
||||
TCPIP_APIMSG_ACK(msg);
|
||||
}
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
/**
|
||||
* See if more data needs to be written from a previous call to netconn_write.
|
||||
* Called initially from lwip_netconn_do_write. If the first call can't send all data
|
||||
|
||||
@@ -266,11 +266,11 @@ do{\
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
#define LWIP_SET_CLOSE_FLAG() \
|
||||
#define LWIP_SET_CLOSE_FLAG(_flag) \
|
||||
do{\
|
||||
LWIP_SOCK_LOCK(__sock);\
|
||||
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mark sock closing\n"));\
|
||||
__sock->state = LWIP_SOCK_CLOSING;\
|
||||
__sock->state = (_flag);\
|
||||
LWIP_SOCK_UNLOCK(__sock);\
|
||||
}while(0)
|
||||
|
||||
@@ -3312,8 +3312,11 @@ int
|
||||
lwip_close_r(int s)
|
||||
{
|
||||
LWIP_API_LOCK();
|
||||
LWIP_SET_CLOSE_FLAG();
|
||||
LWIP_SET_CLOSE_FLAG(LWIP_SOCK_CLOSING);
|
||||
__ret = lwip_close(s);
|
||||
if (EWOULDBLOCK == __sock->err) {
|
||||
LWIP_SET_CLOSE_FLAG(LWIP_SOCK_OPEN);
|
||||
}
|
||||
LWIP_API_UNLOCK();
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,13 @@ sys_thread_t g_lwip_task = NULL;
|
||||
sys_mutex_t lock_tcpip_core;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
#if LWIP_TIMERS
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
#define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg)
|
||||
#else /* LWIP_TIMERS */
|
||||
/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
|
||||
#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
|
||||
#endif /* LWIP_TIMERS */
|
||||
|
||||
/**
|
||||
* The main lwIP thread. This thread has exclusive access to lwIP core functions
|
||||
@@ -99,7 +106,7 @@ tcpip_thread(void *arg)
|
||||
UNLOCK_TCPIP_CORE();
|
||||
LWIP_TCPIP_THREAD_ALIVE();
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
|
||||
TCPIP_MBOX_FETCH(&mbox, (void **)&msg);
|
||||
LOCK_TCPIP_CORE();
|
||||
|
||||
|
||||
|
||||
@@ -133,16 +133,14 @@ bool ip4_netif_exist(const ip4_addr_t *src, const ip4_addr_t *dest)
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Source based IPv4 routing hook function. This function works only
|
||||
* when destination IP is broadcast IP.
|
||||
* Source based IPv4 routing hook function.
|
||||
*/
|
||||
struct netif *
|
||||
ip4_route_src_hook(const ip4_addr_t *dest, const ip4_addr_t *src)
|
||||
{
|
||||
struct netif *netif = NULL;
|
||||
|
||||
/* destination IP is broadcast IP? */
|
||||
if ((src != NULL) && (dest->addr == IPADDR_BROADCAST)) {
|
||||
if ((src != NULL) && !ip4_addr_isany(src)) {
|
||||
/* iterate through netifs */
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
/* is the netif up, does it have a link and a valid address? */
|
||||
|
||||
@@ -453,10 +453,10 @@ void
|
||||
netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr)
|
||||
{
|
||||
ip4_addr_t new_addr = (ipaddr ? *ipaddr : *IP4_ADDR_ANY);
|
||||
#if ESP_LWIP
|
||||
#if ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES
|
||||
ip4_addr_t *last_addr = ip_2_ip4(&netif->last_ip_addr);
|
||||
#else
|
||||
ip4_addr_t *last_addr = netif_ip4_addr(netif);
|
||||
ip4_addr_t *last_addr = ip_2_ip4(&(netif->ip_addr));
|
||||
#endif
|
||||
|
||||
/* address is actually being changed? */
|
||||
|
||||
@@ -149,6 +149,22 @@ tcp_tmr(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
|
||||
/** Called when a listen pcb is closed. Iterates one pcb list and removes the
|
||||
* closed listener pcb from pcb->listener if matching.
|
||||
*/
|
||||
static void
|
||||
tcp_remove_listener(struct tcp_pcb *list, struct tcp_pcb_listen *lpcb)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
for (pcb = list; pcb != NULL; pcb = pcb->next) {
|
||||
if (pcb->listener == lpcb) {
|
||||
pcb->listener = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
tcp_set_fin_wait_1(struct tcp_pcb *pcb)
|
||||
{
|
||||
@@ -158,6 +174,70 @@ tcp_set_fin_wait_1(struct tcp_pcb *pcb)
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Called when a listen pcb is closed. Iterates all pcb lists and removes the
|
||||
* closed listener pcb from pcb->listener if matching.
|
||||
*/
|
||||
static void
|
||||
tcp_listen_closed(struct tcp_pcb *pcb)
|
||||
{
|
||||
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
|
||||
size_t i;
|
||||
LWIP_ASSERT("pcb != NULL", pcb != NULL);
|
||||
LWIP_ASSERT("pcb->state == LISTEN", pcb->state == LISTEN);
|
||||
for (i = 1; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
|
||||
tcp_remove_listener(*tcp_pcb_lists[i], (struct tcp_pcb_listen *)pcb);
|
||||
}
|
||||
#endif
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
}
|
||||
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
/** @ingroup tcp_raw
|
||||
* Delay accepting a connection in respect to the listen backlog:
|
||||
* the number of outstanding connections is increased until
|
||||
* tcp_backlog_accepted() is called.
|
||||
*
|
||||
* ATTENTION: the caller is responsible for calling tcp_backlog_accepted()
|
||||
* or else the backlog feature will get out of sync!
|
||||
*
|
||||
* @param pcb the connection pcb which is not fully accepted yet
|
||||
*/
|
||||
void
|
||||
tcp_backlog_delayed(struct tcp_pcb *pcb)
|
||||
{
|
||||
LWIP_ASSERT("pcb != NULL", pcb != NULL);
|
||||
if ((pcb->flags & TF_BACKLOGPEND) == 0) {
|
||||
if (pcb->listener != NULL) {
|
||||
pcb->listener->accepts_pending++;
|
||||
LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0);
|
||||
pcb->flags |= TF_BACKLOGPEND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @ingroup tcp_raw
|
||||
* A delayed-accept a connection is accepted (or closed/aborted): decreases
|
||||
* the number of outstanding connections after calling tcp_backlog_delayed().
|
||||
*
|
||||
* ATTENTION: the caller is responsible for calling tcp_backlog_accepted()
|
||||
* or else the backlog feature will get out of sync!
|
||||
*
|
||||
* @param pcb the connection pcb which is now fully accepted (or closed/aborted)
|
||||
*/
|
||||
void
|
||||
tcp_backlog_accepted(struct tcp_pcb *pcb)
|
||||
{
|
||||
LWIP_ASSERT("pcb != NULL", pcb != NULL);
|
||||
if ((pcb->flags & TF_BACKLOGPEND) != 0) {
|
||||
if (pcb->listener != NULL) {
|
||||
LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0);
|
||||
pcb->listener->accepts_pending--;
|
||||
pcb->flags &= ~TF_BACKLOGPEND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
/**
|
||||
* Closes the TX side of a connection held by the PCB.
|
||||
* For tcp_close(), a RST is sent if the application didn't receive all data
|
||||
@@ -227,6 +307,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
|
||||
break;
|
||||
case LISTEN:
|
||||
err = ERR_OK;
|
||||
tcp_listen_closed(pcb);
|
||||
tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);
|
||||
memp_free(MEMP_TCP_PCB_LISTEN, pcb);
|
||||
pcb = NULL;
|
||||
@@ -241,6 +322,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
|
||||
case SYN_RCVD:
|
||||
err = tcp_send_fin(pcb);
|
||||
if (err == ERR_OK) {
|
||||
tcp_backlog_accepted(pcb);
|
||||
MIB2_STATS_INC(mib2.tcpattemptfails);
|
||||
tcp_set_fin_wait_1(pcb);
|
||||
}
|
||||
@@ -408,6 +490,7 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||
pcb->ooseq = NULL;
|
||||
}
|
||||
#endif /* TCP_QUEUE_OOSEQ */
|
||||
tcp_backlog_accepted(pcb);
|
||||
if (send_rst) {
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
|
||||
tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port);
|
||||
@@ -1747,27 +1830,7 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
|
||||
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
if (pcb->state == SYN_RCVD) {
|
||||
/* Need to find the corresponding listen_pcb and decrease its accepts_pending */
|
||||
struct tcp_pcb_listen *lpcb;
|
||||
LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL",
|
||||
tcp_listen_pcbs.listen_pcbs != NULL);
|
||||
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
if ((lpcb->local_port == pcb->local_port) &&
|
||||
(IP_IS_V6_VAL(pcb->local_ip) == IP_IS_V6_VAL(lpcb->local_ip)) &&
|
||||
(ip_addr_isany(&lpcb->local_ip) ||
|
||||
ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
|
||||
/* port and address of the listen pcb match the timed-out pcb */
|
||||
LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
|
||||
lpcb->accepts_pending > 0);
|
||||
lpcb->accepts_pending--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
tcp_backlog_accepted(pcb);
|
||||
|
||||
if (pcb->refused_data != NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
|
||||
@@ -1917,6 +1980,31 @@ tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest
|
||||
}
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
/** Helper function for tcp_netif_ip4_addr_changed() that iterates a pcb list */
|
||||
static void
|
||||
tcp_netif_ip_addr_changed_pcblist(const ip4_addr_t* old_addr, struct tcp_pcb* pcb_list)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
pcb = pcb_list;
|
||||
while (pcb != NULL) {
|
||||
/* PCB bound to current local interface address? */
|
||||
if (ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), old_addr)
|
||||
#if LWIP_AUTOIP
|
||||
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
|
||||
&& (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip)))
|
||||
#endif /* LWIP_AUTOIP */
|
||||
) {
|
||||
/* this connection must be aborted */
|
||||
struct tcp_pcb *next = pcb->next;
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
|
||||
tcp_abort(pcb);
|
||||
pcb = next;
|
||||
} else {
|
||||
pcb = pcb->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_IPV4
|
||||
/** This function is called from netif.c when address is changed or netif is removed
|
||||
*
|
||||
@@ -1927,18 +2015,29 @@ void tcp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* n
|
||||
{
|
||||
struct tcp_pcb_listen *lpcb, *next;
|
||||
|
||||
if (!ip4_addr_isany(new_addr)) {
|
||||
/* PCB bound to current local interface address? */
|
||||
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) {
|
||||
next = lpcb->next;
|
||||
/* Is this an IPv4 pcb? */
|
||||
if (!IP_IS_V6_VAL(lpcb->local_ip)) {
|
||||
/* PCB bound to current local interface address? */
|
||||
if ((!(ip4_addr_isany(ip_2_ip4(&lpcb->local_ip)))) &&
|
||||
(ip4_addr_cmp(ip_2_ip4(&lpcb->local_ip), old_addr))) {
|
||||
/* The PCB is listening to the old ipaddr and
|
||||
* is set to listen to the new one instead */
|
||||
ip_addr_copy_from_ip4(lpcb->local_ip, *new_addr);
|
||||
if (!ip4_addr_isany(old_addr)) {
|
||||
#if ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES
|
||||
if ((new_addr == NULL) || ((!ip4_addr_isany_val(*new_addr)) && (!ip4_addr_cmp(old_addr, new_addr)))) {
|
||||
#endif
|
||||
tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_active_pcbs);
|
||||
tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_bound_pcbs);
|
||||
#if ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ip4_addr_isany(new_addr)) {
|
||||
/* PCB bound to current local interface address? */
|
||||
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) {
|
||||
next = lpcb->next;
|
||||
/* Is this an IPv4 pcb? */
|
||||
if (!IP_IS_V6_VAL(lpcb->local_ip)) {
|
||||
/* PCB bound to current local interface address? */
|
||||
if ((!(ip4_addr_isany(ip_2_ip4(&lpcb->local_ip)))) &&
|
||||
(ip4_addr_cmp(ip_2_ip4(&lpcb->local_ip), old_addr))) {
|
||||
/* The PCB is listening to the old ipaddr and
|
||||
* is set to listen to the new one instead */
|
||||
ip_addr_copy_from_ip4(lpcb->local_ip, *new_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,6 +568,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
}
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
pcb->accepts_pending++;
|
||||
npcb->flags |= TF_BACKLOGPEND;
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
/* Set up the new PCB. */
|
||||
ip_addr_copy(npcb->local_ip, *ip_current_dest_addr());
|
||||
@@ -582,6 +583,10 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
#if LWIP_CALLBACK_API
|
||||
npcb->accept = pcb->accept;
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
|
||||
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
|
||||
npcb->listener = pcb;
|
||||
#endif
|
||||
/* inherit socket options */
|
||||
npcb->so_options = pcb->so_options & SOF_INHERITED;
|
||||
/* Register the new PCB so that we can begin receiving segments
|
||||
@@ -785,11 +790,19 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
|
||||
pcb->state = ESTABLISHED;
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
|
||||
#if LWIP_CALLBACK_API
|
||||
LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
|
||||
#endif
|
||||
/* Call the accept function. */
|
||||
TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
|
||||
|
||||
if (pcb->listener == NULL) {
|
||||
err = ERR_VAL;
|
||||
} else {
|
||||
#endif
|
||||
tcp_backlog_accepted(pcb);
|
||||
/* Call the accept function. */
|
||||
TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
|
||||
}
|
||||
if (err != ERR_OK) {
|
||||
/* If the accept function returns with an error, we abort
|
||||
* the connection. */
|
||||
|
||||
@@ -44,8 +44,6 @@
|
||||
#include "lwip/timers.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
|
||||
#if LWIP_TIMERS
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
@@ -62,11 +60,64 @@
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
#define HANDLER(x) x, #x
|
||||
#else /* LWIP_DEBUG_TIMERNAMES */
|
||||
#define HANDLER(x) x
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
|
||||
#if ESP_DHCP
|
||||
extern void dhcps_coarse_tmr(void);
|
||||
#endif
|
||||
|
||||
/** This array contains all stack-internal cyclic timers. To get the number of
|
||||
* timers, use LWIP_ARRAYSIZE() */
|
||||
const struct lwip_cyclic_timer lwip_cyclic_timers[] = {
|
||||
#if LWIP_TCP
|
||||
/* The TCP timer is a special case: it does not have to run always and
|
||||
* is triggered to start from TCP using tcp_timer_needed() */
|
||||
{TCP_TMR_INTERVAL, HANDLER(tcp_tmr)},
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_IPV4
|
||||
#if IP_REASSEMBLY
|
||||
{IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)},
|
||||
#endif /* IP_REASSEMBLY */
|
||||
#if LWIP_ARP
|
||||
{ARP_TMR_INTERVAL, HANDLER(etharp_tmr)},
|
||||
#endif /* LWIP_ARP */
|
||||
#if LWIP_DHCP
|
||||
{DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)},
|
||||
{DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)},
|
||||
#if ESP_DHCP
|
||||
{DHCP_COARSE_TIMER_MSECS, HANDLER(dhcps_coarse_tmr)},
|
||||
#endif
|
||||
#endif /* LWIP_DHCP */
|
||||
#if LWIP_AUTOIP
|
||||
{AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)},
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_IGMP
|
||||
{IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)},
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_DNS
|
||||
{DNS_TMR_INTERVAL, HANDLER(dns_tmr)},
|
||||
#endif /* LWIP_DNS */
|
||||
#if LWIP_IPV6
|
||||
{ND6_TMR_INTERVAL, HANDLER(nd6_tmr)},
|
||||
#if LWIP_IPV6_REASS
|
||||
{IP6_REASS_TMR_INTERVAL, HANDLER(ip6_reass_tmr)},
|
||||
#endif /* LWIP_IPV6_REASS */
|
||||
#if LWIP_IPV6_MLD
|
||||
{MLD6_TMR_INTERVAL, HANDLER(mld6_tmr)},
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
};
|
||||
|
||||
#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM
|
||||
|
||||
/** The one and only timeout list */
|
||||
static struct sys_timeo *next_timeout;
|
||||
#if NO_SYS
|
||||
static u32_t timeouts_last_time;
|
||||
#endif /* NO_SYS */
|
||||
|
||||
#if LWIP_TCP
|
||||
/** global variable that shows if the tcp timer is currently scheduled or not */
|
||||
@@ -111,213 +162,35 @@ tcp_timer_needed(void)
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
#if LWIP_IPV4
|
||||
#if IP_REASSEMBLY
|
||||
/**
|
||||
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
ip_reass_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
|
||||
ip_reass_tmr();
|
||||
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
|
||||
}
|
||||
#endif /* IP_REASSEMBLY */
|
||||
|
||||
#if LWIP_ARP
|
||||
/**
|
||||
* Timer callback function that calls etharp_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
arp_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
|
||||
etharp_tmr();
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_ARP */
|
||||
|
||||
#if LWIP_DHCP
|
||||
/**
|
||||
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dhcp_timer_coarse(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
|
||||
dhcp_coarse_tmr();
|
||||
|
||||
#if ESP_DHCP
|
||||
extern void dhcps_coarse_tmr(void);
|
||||
dhcps_coarse_tmr();
|
||||
#endif
|
||||
|
||||
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dhcp_timer_fine(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
|
||||
dhcp_fine_tmr();
|
||||
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
|
||||
}
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
#if LWIP_AUTOIP
|
||||
/**
|
||||
* Timer callback function that calls autoip_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
autoip_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
|
||||
autoip_tmr();
|
||||
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
#if LWIP_IGMP
|
||||
/**
|
||||
* Timer callback function that calls igmp_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
igmp_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
|
||||
igmp_tmr();
|
||||
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
#if LWIP_DNS
|
||||
/**
|
||||
* Timer callback function that calls dns_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dns_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
|
||||
dns_tmr();
|
||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Timer callback function that calls nd6_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
nd6_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n"));
|
||||
nd6_tmr();
|
||||
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
|
||||
}
|
||||
|
||||
#if LWIP_IPV6_REASS
|
||||
/**
|
||||
* Timer callback function that calls ip6_reass_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
ip6_reass_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n"));
|
||||
ip6_reass_tmr();
|
||||
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_IPV6_REASS */
|
||||
|
||||
#if LWIP_IPV6_MLD
|
||||
/**
|
||||
* Timer callback function that calls mld6_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
mld6_timer(void *arg)
|
||||
cyclic_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n"));
|
||||
mld6_tmr();
|
||||
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
|
||||
const struct lwip_cyclic_timer* cyclic = (const struct lwip_cyclic_timer*)arg;
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: %s()\n", cyclic->handler_name));
|
||||
#endif
|
||||
cyclic->handler();
|
||||
sys_timeout(cyclic->interval_ms, cyclic_timer, arg);
|
||||
}
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/** Initialize this module */
|
||||
void sys_timeouts_init(void)
|
||||
{
|
||||
#if LWIP_IPV4
|
||||
#if IP_REASSEMBLY
|
||||
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
|
||||
#endif /* IP_REASSEMBLY */
|
||||
#if LWIP_ARP
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
#endif /* LWIP_ARP */
|
||||
#if LWIP_DHCP
|
||||
size_t i;
|
||||
/* tcp_tmr() at index 0 is started on demand */
|
||||
for (i = (LWIP_TCP ? 1 : 0); i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) {
|
||||
/* we have to cast via size_t to get rid of const warning
|
||||
* (this is OK as cyclic_timer() casts back to const* */
|
||||
sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, LWIP_CONST_CAST(void*, &lwip_cyclic_timers[i]));
|
||||
}
|
||||
|
||||
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
|
||||
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
|
||||
#endif /* LWIP_DHCP */
|
||||
#if LWIP_AUTOIP
|
||||
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_IGMP
|
||||
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
#if LWIP_DNS
|
||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
#if LWIP_IPV6
|
||||
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
|
||||
#if LWIP_IPV6_REASS
|
||||
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
|
||||
#endif /* LWIP_IPV6_REASS */
|
||||
#if LWIP_IPV6_MLD
|
||||
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if NO_SYS
|
||||
/* Initialise timestamp for sys_check_timeouts */
|
||||
timeouts_last_time = sys_now();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -334,19 +207,12 @@ void sys_timeouts_init(void)
|
||||
void
|
||||
sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
|
||||
#else /* LWIP_DEBUG_TIMERNAMES */
|
||||
|
||||
#if ESP_LIGHT_SLEEP
|
||||
u32_t LwipTimOutLim = 0; // For light sleep. time out. limit is 3000ms
|
||||
#endif
|
||||
|
||||
void
|
||||
sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
{
|
||||
struct sys_timeo *timeout, *t;
|
||||
#if NO_SYS
|
||||
u32_t now, diff;
|
||||
#endif
|
||||
|
||||
timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
|
||||
if (timeout == NULL) {
|
||||
@@ -354,7 +220,6 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
#if NO_SYS
|
||||
now = sys_now();
|
||||
if (next_timeout == NULL) {
|
||||
diff = 0;
|
||||
@@ -362,26 +227,15 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
|
||||
} else {
|
||||
diff = now - timeouts_last_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
timeout->next = NULL;
|
||||
timeout->h = handler;
|
||||
timeout->arg = arg;
|
||||
|
||||
#if ESP_LIGHT_SLEEP
|
||||
if(msecs < LwipTimOutLim)
|
||||
msecs = LwipTimOutLim;
|
||||
#endif
|
||||
|
||||
#if NO_SYS
|
||||
timeout->time = msecs + diff;
|
||||
#else
|
||||
timeout->time = msecs;
|
||||
#endif
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
timeout->handler_name = handler_name;
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
|
||||
(void *)timeout, msecs, handler_name, (void *)arg));
|
||||
(void *)timeout, msecs, handler_name, (void *)arg));
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
|
||||
if (next_timeout == NULL) {
|
||||
@@ -399,6 +253,12 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
|
||||
if (t->next == NULL || t->next->time > timeout->time) {
|
||||
if (t->next != NULL) {
|
||||
t->next->time -= timeout->time;
|
||||
} else if (timeout->time > msecs) {
|
||||
/* If this is the case, 'timeouts_last_time' and 'now' differs too much.
|
||||
* This can be due to sys_check_timeouts() not being called at the right
|
||||
* times, but also when stopping in a breakpoint. Anyway, let's assume
|
||||
* this is not wanted, so add the first timer's time instead of 'diff' */
|
||||
timeout->time = msecs + next_timeout->time;
|
||||
}
|
||||
timeout->next = t->next;
|
||||
t->next = timeout;
|
||||
@@ -415,7 +275,7 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
|
||||
*
|
||||
* @param handler callback function that would be called by the timeout
|
||||
* @param arg callback argument that would be passed to handler
|
||||
*/
|
||||
*/
|
||||
void
|
||||
sys_untimeout(sys_timeout_handler handler, void *arg)
|
||||
{
|
||||
@@ -445,14 +305,17 @@ sys_untimeout(sys_timeout_handler handler, void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
#if NO_SYS
|
||||
|
||||
/** Handle timeouts for NO_SYS==1 (i.e. without using
|
||||
/**
|
||||
* @ingroup lwip_nosys
|
||||
* Handle timeouts for NO_SYS==1 (i.e. without using
|
||||
* tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
|
||||
* handler functions when timeouts expire.
|
||||
*
|
||||
* Must be called periodically from your main loop.
|
||||
*/
|
||||
#if !NO_SYS && !defined __DOXYGEN__
|
||||
static
|
||||
#endif /* !NO_SYS */
|
||||
void
|
||||
sys_check_timeouts(void)
|
||||
{
|
||||
@@ -468,9 +331,7 @@ sys_check_timeouts(void)
|
||||
/* this cares for wraparounds */
|
||||
diff = now - timeouts_last_time;
|
||||
do {
|
||||
#if PBUF_POOL_FREE_OOSEQ
|
||||
PBUF_CHECK_FREE_OOSEQ();
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||
had_one = 0;
|
||||
tmptimeout = next_timeout;
|
||||
if (tmptimeout && (tmptimeout->time <= diff)) {
|
||||
@@ -483,16 +344,24 @@ sys_check_timeouts(void)
|
||||
arg = tmptimeout->arg;
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
if (handler != NULL) {
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
|
||||
tmptimeout->handler_name, arg));
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",tmptimeout->handler_name, arg));
|
||||
}
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
if (handler != NULL) {
|
||||
#if !NO_SYS
|
||||
/* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
|
||||
* timeout handler function. */
|
||||
LOCK_TCPIP_CORE();
|
||||
#endif /* !NO_SYS */
|
||||
handler(arg);
|
||||
#if !NO_SYS
|
||||
UNLOCK_TCPIP_CORE();
|
||||
#endif /* !NO_SYS */
|
||||
}
|
||||
LWIP_TCPIP_THREAD_ALIVE();
|
||||
}
|
||||
/* repeat until all expired timers have been called */
|
||||
/* repeat until all expired timers have been called */
|
||||
} while (had_one);
|
||||
}
|
||||
}
|
||||
@@ -511,6 +380,9 @@ sys_restart_timeouts(void)
|
||||
/** Return the time left before the next timeout is due. If no timeouts are
|
||||
* enqueued, returns 0xffffffff
|
||||
*/
|
||||
#if !NO_SYS
|
||||
static
|
||||
#endif /* !NO_SYS */
|
||||
u32_t
|
||||
sys_timeouts_sleeptime(void)
|
||||
{
|
||||
@@ -526,7 +398,7 @@ sys_timeouts_sleeptime(void)
|
||||
}
|
||||
}
|
||||
|
||||
#else /* NO_SYS */
|
||||
#if !NO_SYS
|
||||
|
||||
/**
|
||||
* Wait (forever) for a message to arrive in an mbox.
|
||||
@@ -538,66 +410,30 @@ sys_timeouts_sleeptime(void)
|
||||
void
|
||||
sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
|
||||
{
|
||||
u32_t time_needed;
|
||||
struct sys_timeo *tmptimeout;
|
||||
sys_timeout_handler handler;
|
||||
void *arg;
|
||||
|
||||
again:
|
||||
u32_t sleeptime;
|
||||
again:
|
||||
if (!next_timeout) {
|
||||
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
|
||||
} else {
|
||||
if (next_timeout->time > 0) {
|
||||
time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
|
||||
} else {
|
||||
time_needed = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
sys_arch_mbox_fetch(mbox, msg, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_needed == SYS_ARCH_TIMEOUT) {
|
||||
/* If time == SYS_ARCH_TIMEOUT, a timeout occurred before a message
|
||||
could be fetched. We should now call the timeout handler and
|
||||
deallocate the memory allocated for the timeout. */
|
||||
tmptimeout = next_timeout;
|
||||
next_timeout = tmptimeout->next;
|
||||
handler = tmptimeout->h;
|
||||
arg = tmptimeout->arg;
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
if (handler != NULL) {
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
|
||||
tmptimeout->handler_name, arg));
|
||||
}
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
if (handler != NULL) {
|
||||
/* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
|
||||
timeout handler function. */
|
||||
LOCK_TCPIP_CORE();
|
||||
handler(arg);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
}
|
||||
LWIP_TCPIP_THREAD_ALIVE();
|
||||
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
} else {
|
||||
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
||||
occured. The time variable is set to the number of
|
||||
milliseconds we waited for the message. */
|
||||
if (time_needed < next_timeout->time) {
|
||||
next_timeout->time -= time_needed;
|
||||
} else {
|
||||
next_timeout->time = 0;
|
||||
}
|
||||
}
|
||||
sleeptime = sys_timeouts_sleeptime();
|
||||
if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) {
|
||||
/* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
|
||||
* before a message could be fetched. */
|
||||
sys_check_timeouts();
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NO_SYS */
|
||||
|
||||
#else /* LWIP_TIMERS */
|
||||
#else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */
|
||||
/* Satisfy the TCP code which calls this function */
|
||||
void
|
||||
tcp_timer_needed(void)
|
||||
{
|
||||
}
|
||||
#endif /* LWIP_TIMERS */
|
||||
#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@
|
||||
#define X8_F "02x"
|
||||
#endif /* X8_F */
|
||||
|
||||
/** C++ const_cast<target_type>(val) equivalent to remove constness from a value (GCC -Wcast-qual) */
|
||||
#ifndef LWIP_CONST_CAST
|
||||
#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -47,6 +47,8 @@ extern "C" {
|
||||
#define IPADDR_TYPE_V6 6U
|
||||
#define IPADDR_TYPE_ANY 46U
|
||||
|
||||
#define IP_IS_V4_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4)
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
/** A union struct for both IP version's addresses.
|
||||
* ATTENTION: watch out for its size when adding IPv6 address scope!
|
||||
@@ -67,6 +69,7 @@ extern const ip_addr_t ip_addr_any_type;
|
||||
#define IP_IS_ANY_TYPE_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_ANY)
|
||||
#define IPADDR_ANY_TYPE_INIT { { { { 0ul, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_ANY }
|
||||
|
||||
#define IP_IS_V4_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4)
|
||||
#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6)
|
||||
#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr)))
|
||||
|
||||
|
||||
@@ -69,11 +69,16 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
|
||||
* Mainly for compatibility to old versions.
|
||||
* LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers.
|
||||
* (the array of lwip-internal cyclic timers is still provided)
|
||||
* (check NO_SYS_NO_TIMERS for compatibility to old versions)
|
||||
*/
|
||||
#ifndef NO_SYS_NO_TIMERS
|
||||
#define NO_SYS_NO_TIMERS 0
|
||||
#if !defined LWIP_TIMERS || defined __DOXYGEN__
|
||||
#ifdef NO_SYS_NO_TIMERS
|
||||
#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))
|
||||
#else
|
||||
#define LWIP_TIMERS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
@@ -169,12 +169,12 @@ struct pbuf_custom {
|
||||
};
|
||||
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
|
||||
|
||||
#if LWIP_TCP && TCP_QUEUE_OOSEQ
|
||||
|
||||
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
|
||||
#ifndef PBUF_POOL_FREE_OOSEQ
|
||||
#define PBUF_POOL_FREE_OOSEQ 1
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||
#if NO_SYS && PBUF_POOL_FREE_OOSEQ
|
||||
#if LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ
|
||||
extern volatile u8_t pbuf_free_ooseq_pending;
|
||||
void pbuf_free_ooseq(void);
|
||||
/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ()
|
||||
@@ -184,8 +184,10 @@ void pbuf_free_ooseq(void);
|
||||
/* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \
|
||||
ooseq queued pbufs now */ \
|
||||
pbuf_free_ooseq(); }}while(0)
|
||||
#endif /* NO_SYS && PBUF_POOL_FREE_OOSEQ*/
|
||||
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ */
|
||||
#else /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ */
|
||||
/* Otherwise declare an empty PBUF_CHECK_FREE_OOSEQ */
|
||||
#define PBUF_CHECK_FREE_OOSEQ()
|
||||
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ*/
|
||||
|
||||
/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
|
||||
#define pbuf_init()
|
||||
|
||||
@@ -232,6 +232,9 @@ void lwip_netconn_do_disconnect (void *m);
|
||||
void lwip_netconn_do_listen (void *m);
|
||||
void lwip_netconn_do_send (void *m);
|
||||
void lwip_netconn_do_recv (void *m);
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
void lwip_netconn_do_accepted (void *m);
|
||||
#endif
|
||||
void lwip_netconn_do_write (void *m);
|
||||
void lwip_netconn_do_getaddr (void *m);
|
||||
void lwip_netconn_do_close (void *m);
|
||||
|
||||
@@ -138,7 +138,7 @@ typedef u16_t tcpflags_t;
|
||||
#define TCPWND16(x) (x)
|
||||
#define TCP_WND_MAX(pcb) TCP_WND(pcb)
|
||||
typedef u16_t tcpwnd_size_t;
|
||||
typedef u8_t tcpflags_t;
|
||||
typedef u16_t tcpflags_t;
|
||||
#endif
|
||||
|
||||
enum tcp_state {
|
||||
@@ -203,6 +203,9 @@ struct tcp_pcb {
|
||||
#define TF_NAGLEMEMERR 0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
|
||||
#if LWIP_WND_SCALE
|
||||
#define TF_WND_SCALE 0x0100U /* Window Scale option enabled */
|
||||
#endif
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
#define TF_BACKLOGPEND 0x0200U /* If this is set, a connection pcb has increased the backlog on its listener */
|
||||
#endif
|
||||
|
||||
/* the rest of the fields are in host byte order
|
||||
@@ -311,6 +314,10 @@ struct tcp_pcb {
|
||||
u8_t rcv_scale;
|
||||
#endif
|
||||
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
struct tcp_pcb_listen *listener;
|
||||
#endif
|
||||
|
||||
#if ESP_STATS_TCP
|
||||
#define ESP_STATS_TCP_ARRAY_SIZE 20
|
||||
u16_t retry_cnt[TCP_MAXRTX];
|
||||
@@ -383,16 +390,17 @@ void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err);
|
||||
#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0)
|
||||
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
#define tcp_accepted(pcb) do { \
|
||||
LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \
|
||||
(((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0)
|
||||
#define tcp_backlog_set(pcb, new_backlog) do { \
|
||||
LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", (pcb)->state == LISTEN); \
|
||||
((struct tcp_pcb_listen *)(pcb))->backlog = ((new_backlog) ? (new_backlog) : 1); } while(0)
|
||||
void tcp_backlog_delayed(struct tcp_pcb* pcb);
|
||||
void tcp_backlog_accepted(struct tcp_pcb* pcb);
|
||||
#else /* TCP_LISTEN_BACKLOG */
|
||||
#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \
|
||||
(pcb)->state == LISTEN)
|
||||
#define tcp_backlog_set(pcb, new_backlog)
|
||||
#define tcp_backlog_delayed(pcb)
|
||||
#define tcp_backlog_accepted(pcb)
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
#define tcp_accepted(pcb) do { LWIP_UNUSED_ARG(pcb); } while(0) /* compatibility define, not needed any more */
|
||||
|
||||
void tcp_recved (struct tcp_pcb *pcb, u16_t len);
|
||||
err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr,
|
||||
|
||||
@@ -34,12 +34,6 @@
|
||||
#define LWIP_HDR_TIMERS_H
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */
|
||||
#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))
|
||||
|
||||
#if LWIP_TIMERS
|
||||
|
||||
#include "lwip/err.h"
|
||||
#if !NO_SYS
|
||||
#include "lwip/sys.h"
|
||||
@@ -57,6 +51,26 @@ extern "C" {
|
||||
#endif /* LWIP_DEBUG*/
|
||||
#endif
|
||||
|
||||
/** Function prototype for a stack-internal timer function that has to be
|
||||
* called at a defined interval */
|
||||
typedef void (* lwip_cyclic_timer_handler)(void);
|
||||
|
||||
/** This struct contains information about a stack-internal timer function
|
||||
* that has to be called at a defined interval */
|
||||
struct lwip_cyclic_timer {
|
||||
u32_t interval_ms;
|
||||
lwip_cyclic_timer_handler handler;
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
const char* handler_name;
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
};
|
||||
|
||||
/** This array contains all stack-internal cyclic timers. To get the number of
|
||||
* timers, use LWIP_ARRAYSIZE() */
|
||||
extern const struct lwip_cyclic_timer lwip_cyclic_timers[];
|
||||
|
||||
#if LWIP_TIMERS
|
||||
|
||||
/** Function prototype for a timeout callback function. Register such a function
|
||||
* using sys_timeout().
|
||||
*
|
||||
@@ -84,18 +98,20 @@ void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg);
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
|
||||
void sys_untimeout(sys_timeout_handler handler, void *arg);
|
||||
void sys_restart_timeouts(void);
|
||||
#if NO_SYS
|
||||
void sys_check_timeouts(void);
|
||||
void sys_restart_timeouts(void);
|
||||
u32_t sys_timeouts_sleeptime(void);
|
||||
#else /* NO_SYS */
|
||||
void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg);
|
||||
#endif /* NO_SYS */
|
||||
|
||||
|
||||
#endif /* LWIP_TIMERS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_TIMERS */
|
||||
#endif /* LWIP_HDR_TIMERS_H */
|
||||
|
||||
|
||||
@@ -294,6 +294,12 @@
|
||||
*/
|
||||
#define TCP_QUEUE_OOSEQ CONFIG_TCP_QUEUE_OOSEQ
|
||||
|
||||
/**
|
||||
* ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES==1: Keep TCP connection when IP changed
|
||||
* scenario happens: 192.168.0.2 -> 0.0.0.0 -> 192.168.0.2 or 192.168.0.2 -> 0.0.0.0
|
||||
*/
|
||||
|
||||
#define ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES
|
||||
/*
|
||||
* LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all
|
||||
* events (accept, sent, etc) that happen in the system.
|
||||
|
||||
@@ -60,7 +60,7 @@ void HashList::insert(const Item& item, size_t index)
|
||||
newBlock->mCount++;
|
||||
}
|
||||
|
||||
void HashList::erase(size_t index)
|
||||
void HashList::erase(size_t index, bool itemShouldExist)
|
||||
{
|
||||
for (auto it = mBlockList.begin(); it != mBlockList.end();) {
|
||||
bool haveEntries = false;
|
||||
@@ -82,7 +82,9 @@ void HashList::erase(size_t index)
|
||||
++it;
|
||||
}
|
||||
}
|
||||
assert(false && "item should have been present in cache");
|
||||
if (itemShouldExist) {
|
||||
assert(false && "item should have been present in cache");
|
||||
}
|
||||
}
|
||||
|
||||
size_t HashList::find(size_t start, const Item& item)
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
~HashList();
|
||||
|
||||
void insert(const Item& item, size_t index);
|
||||
void erase(const size_t index);
|
||||
void erase(const size_t index, bool itemShouldExist=true);
|
||||
size_t find(size_t start, const Item& item);
|
||||
void clear();
|
||||
|
||||
|
||||
@@ -314,7 +314,6 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
|
||||
{
|
||||
auto state = mEntryTable.get(index);
|
||||
assert(state == EntryState::WRITTEN || state == EntryState::EMPTY);
|
||||
mHashList.erase(index);
|
||||
|
||||
size_t span = 1;
|
||||
if (state == EntryState::WRITTEN) {
|
||||
@@ -324,6 +323,7 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
|
||||
return rc;
|
||||
}
|
||||
if (item.calculateCrc32() != item.crc32) {
|
||||
mHashList.erase(index, false);
|
||||
rc = alterEntryState(index, EntryState::ERASED);
|
||||
--mUsedEntryCount;
|
||||
++mErasedEntryCount;
|
||||
@@ -331,6 +331,7 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
mHashList.erase(index);
|
||||
span = item.span;
|
||||
for (ptrdiff_t i = index + span - 1; i >= static_cast<ptrdiff_t>(index); --i) {
|
||||
if (mEntryTable.get(i) == EntryState::WRITTEN) {
|
||||
@@ -511,11 +512,6 @@ esp_err_t Page::mLoadEntryTable()
|
||||
return err;
|
||||
}
|
||||
|
||||
mHashList.insert(item, i);
|
||||
|
||||
// search for potential duplicate item
|
||||
size_t duplicateIndex = mHashList.find(0, item);
|
||||
|
||||
if (item.crc32 != item.calculateCrc32()) {
|
||||
err = eraseEntryAndSpan(i);
|
||||
if (err != ESP_OK) {
|
||||
@@ -525,6 +521,10 @@ esp_err_t Page::mLoadEntryTable()
|
||||
continue;
|
||||
}
|
||||
|
||||
mHashList.insert(item, i);
|
||||
|
||||
// search for potential duplicate item
|
||||
size_t duplicateIndex = mHashList.find(0, item);
|
||||
|
||||
if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) {
|
||||
span = item.span;
|
||||
@@ -576,8 +576,6 @@ esp_err_t Page::mLoadEntryTable()
|
||||
return err;
|
||||
}
|
||||
|
||||
mHashList.insert(item, i);
|
||||
|
||||
if (item.crc32 != item.calculateCrc32()) {
|
||||
err = eraseEntryAndSpan(i);
|
||||
if (err != ESP_OK) {
|
||||
@@ -586,9 +584,11 @@ esp_err_t Page::mLoadEntryTable()
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
assert(item.span > 0);
|
||||
|
||||
mHashList.insert(item, i);
|
||||
|
||||
size_t span = item.span;
|
||||
i += span - 1;
|
||||
}
|
||||
@@ -726,7 +726,11 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si
|
||||
|
||||
auto crc32 = item.calculateCrc32();
|
||||
if (item.crc32 != crc32) {
|
||||
eraseEntryAndSpan(i);
|
||||
rc = eraseEntryAndSpan(i);
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return rc;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -259,6 +259,25 @@ TEST_CASE("Page validates blob size", "[nvs]")
|
||||
TEST_ESP_OK(page.writeItem(1, ItemType::BLOB, "2", buf, Page::BLOB_MAX_SIZE));
|
||||
}
|
||||
|
||||
TEST_CASE("Page handles invalid CRC of variable length items", "[nvs][cur]")
|
||||
{
|
||||
SpiFlashEmulator emu(4);
|
||||
{
|
||||
Page page;
|
||||
TEST_ESP_OK(page.load(0));
|
||||
char buf[128] = {0};
|
||||
TEST_ESP_OK(page.writeItem(1, ItemType::BLOB, "1", buf, sizeof(buf)));
|
||||
}
|
||||
// corrupt header of the item (64 is the offset of the first item in page)
|
||||
uint32_t overwrite_buf = 0;
|
||||
emu.write(64, &overwrite_buf, 4);
|
||||
// load page again
|
||||
{
|
||||
Page page;
|
||||
TEST_ESP_OK(page.load(0));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("can init PageManager in empty flash", "[nvs]")
|
||||
{
|
||||
SpiFlashEmulator emu(4);
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
#define SENS_FORCE_XPD_SAR_M ((SENS_FORCE_XPD_SAR_V)<<(SENS_FORCE_XPD_SAR_S))
|
||||
#define SENS_FORCE_XPD_SAR_V 0x3
|
||||
#define SENS_FORCE_XPD_SAR_S 18
|
||||
#define SENS_FORCE_XPD_SAR_SW_M (BIT1)
|
||||
#define SENS_FORCE_XPD_SAR_FSM 0 // Use FSM to control power down
|
||||
#define SENS_FORCE_XPD_SAR_PD 2 // Force power down
|
||||
#define SENS_FORCE_XPD_SAR_PU 3 // Force power up
|
||||
|
||||
@@ -697,20 +697,23 @@ static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry,
|
||||
esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
|
||||
vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
|
||||
struct spiffs_dirent out;
|
||||
if (SPIFFS_readdir(&dir->d, &out) == 0) {
|
||||
errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
|
||||
SPIFFS_clearerr(efs->fs);
|
||||
if (!errno) {
|
||||
*out_dirent = NULL;
|
||||
size_t plen;
|
||||
char * item_name;
|
||||
do {
|
||||
if (SPIFFS_readdir(&dir->d, &out) == 0) {
|
||||
errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
|
||||
SPIFFS_clearerr(efs->fs);
|
||||
if (!errno) {
|
||||
*out_dirent = NULL;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
const char * item_name = (const char *)out.name;
|
||||
size_t plen = strlen(dir->path);
|
||||
item_name = (char *)out.name;
|
||||
plen = strlen(dir->path);
|
||||
|
||||
} while ((plen > 1) && (strncasecmp(dir->path, (const char*)out.name, plen) || out.name[plen] != '/' || !out.name[plen + 1]));
|
||||
|
||||
if (plen > 1) {
|
||||
if (strncasecmp(dir->path, (const char *)out.name, plen) || out.name[plen] != '/' || !out.name[plen+1]) {
|
||||
return vfs_spiffs_readdir_r(ctx, pdir, entry, out_dirent);
|
||||
}
|
||||
item_name += plen + 1;
|
||||
} else if (item_name[0] == '/') {
|
||||
item_name++;
|
||||
|
||||
@@ -275,6 +275,63 @@ void test_spiffs_opendir_readdir_rewinddir(const char* dir_prefix)
|
||||
TEST_ASSERT_EQUAL(0, closedir(dir));
|
||||
}
|
||||
|
||||
void test_spiffs_readdir_many_files(const char* dir_prefix)
|
||||
{
|
||||
const int n_files = 40;
|
||||
const int n_folders = 4;
|
||||
unsigned char file_count[n_files * n_folders];
|
||||
memset(file_count, 0, sizeof(file_count)/sizeof(file_count[0]));
|
||||
char file_name[ESP_VFS_PATH_MAX + CONFIG_SPIFFS_OBJ_NAME_LEN];
|
||||
|
||||
/* clean stale files before the test */
|
||||
DIR* dir = opendir(dir_prefix);
|
||||
if (dir) {
|
||||
while (true) {
|
||||
struct dirent* de = readdir(dir);
|
||||
if (!de) {
|
||||
break;
|
||||
}
|
||||
snprintf(file_name, sizeof(file_name), "%s/%s", dir_prefix, de->d_name);
|
||||
unlink(file_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* create files */
|
||||
for (int d = 0; d < n_folders; ++d) {
|
||||
printf("filling directory %d\n", d);
|
||||
for (int f = 0; f < n_files; ++f) {
|
||||
snprintf(file_name, sizeof(file_name), "%s/%d/%d.txt", dir_prefix, d, f);
|
||||
test_spiffs_create_file_with_text(file_name, file_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* list files */
|
||||
for (int d = 0; d < n_folders; ++d) {
|
||||
printf("listing files in directory %d\n", d);
|
||||
snprintf(file_name, sizeof(file_name), "%s/%d", dir_prefix, d);
|
||||
dir = opendir(file_name);
|
||||
TEST_ASSERT_NOT_NULL(dir);
|
||||
while (true) {
|
||||
struct dirent* de = readdir(dir);
|
||||
if (!de) {
|
||||
break;
|
||||
}
|
||||
int file_id;
|
||||
TEST_ASSERT_EQUAL(1, sscanf(de->d_name, "%d.txt", &file_id));
|
||||
file_count[file_id + d * n_files]++;
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/* check that all created files have been seen */
|
||||
for (int d = 0; d < n_folders; ++d) {
|
||||
printf("checking that all files have been found in directory %d\n", d);
|
||||
for (int f = 0; f < n_files; ++f) {
|
||||
TEST_ASSERT_EQUAL(1, file_count[f + d * n_files]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char* filename;
|
||||
@@ -499,6 +556,13 @@ TEST_CASE("opendir, readdir, rewinddir, seekdir work as expected", "[spiffs]")
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("readdir with large number of files", "[spiffs][timeout=15]")
|
||||
{
|
||||
test_setup();
|
||||
test_spiffs_readdir_many_files("/spiffs/dir2");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("multiple tasks can use same volume", "[spiffs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
@@ -81,7 +81,7 @@ build: $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_HEADER) \
|
||||
$(ULP_EXP_DEP_OBJECTS) : $(ULP_EXPORTS_HEADER) $(ULP_SYM)
|
||||
|
||||
# Finally, set all the variables processed by the build system.
|
||||
COMPONENT_EXTRA_CLEAN := $(ULP_OBJECTS) \
|
||||
COMPONENT_EXTRA_CLEAN += $(ULP_OBJECTS) \
|
||||
$(ULP_LD_SCRIPT) \
|
||||
$(ULP_PREPROCESSED) \
|
||||
$(ULP_ELF) $(ULP_BIN) \
|
||||
@@ -91,6 +91,6 @@ COMPONENT_EXTRA_CLEAN := $(ULP_OBJECTS) \
|
||||
$(ULP_DEP) \
|
||||
$(ULP_LISTINGS)
|
||||
|
||||
COMPONENT_EMBED_FILES := $(COMPONENT_BUILD_DIR)/$(ULP_BIN)
|
||||
COMPONENT_ADD_LDFLAGS := -l$(COMPONENT_NAME) -T $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD)
|
||||
COMPONENT_EXTRA_INCLUDES := $(COMPONENT_BUILD_DIR)
|
||||
COMPONENT_EMBED_FILES += $(COMPONENT_BUILD_DIR)/$(ULP_BIN)
|
||||
COMPONENT_ADD_LDFLAGS += -l$(COMPONENT_NAME) -T $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD)
|
||||
COMPONENT_EXTRA_INCLUDES += $(COMPONENT_BUILD_DIR)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_err.h"
|
||||
#include "soc/soc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -857,7 +858,7 @@ esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* prog
|
||||
* 3. TEXT_SIZE, size of .text section (2 bytes)
|
||||
* 4. DATA_SIZE, size of .data section (2 bytes)
|
||||
* 5. BSS_SIZE, size of .bss section (2 bytes)
|
||||
* 6. (TEXT_OFFSET - 16) bytes of arbitrary data (will not be loaded into RTC memory)
|
||||
* 6. (TEXT_OFFSET - 12) bytes of arbitrary data (will not be loaded into RTC memory)
|
||||
* 7. .text section
|
||||
* 8. .data section
|
||||
*
|
||||
|
||||
@@ -1 +1,11 @@
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
ULP_APP_NAME = ulp_test
|
||||
|
||||
ULP_S_SOURCES = $(addprefix $(COMPONENT_PATH)/ulp/, \
|
||||
test_jumps.S \
|
||||
)
|
||||
|
||||
ULP_EXP_DEP_OBJECTS := test_ulp_as.o
|
||||
|
||||
include $(IDF_PATH)/components/ulp/component_ulp_common.mk
|
||||
|
||||
COMPONENT_ADD_LDFLAGS += -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
|
||||
25
components/ulp/test/test_ulp_as.c
Normal file
25
components/ulp/test/test_ulp_as.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <unistd.h>
|
||||
#include "unity.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "esp32/ulp.h"
|
||||
#include "ulp_test.h"
|
||||
|
||||
|
||||
extern const uint8_t ulp_test_bin_start[] asm("_binary_ulp_test_bin_start");
|
||||
extern const uint8_t ulp_test_bin_end[] asm("_binary_ulp_test_bin_end");
|
||||
|
||||
|
||||
TEST_CASE("jumps condition", "[ulp]")
|
||||
{
|
||||
esp_err_t err = ulp_load_binary(0, ulp_test_bin_start,
|
||||
(ulp_test_bin_end - ulp_test_bin_start) / sizeof(uint32_t));
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
REG_CLR_BIT(RTC_CNTL_INT_RAW_REG, RTC_CNTL_ULP_CP_INT_RAW);
|
||||
TEST_ESP_OK(ulp_run(&ulp_test_jumps - RTC_SLOW_MEM));
|
||||
usleep(10000);
|
||||
|
||||
TEST_ASSERT_NOT_EQUAL(0, REG_GET_BIT(RTC_CNTL_INT_RAW_REG, RTC_CNTL_ULP_CP_INT_RAW));
|
||||
TEST_ASSERT_EQUAL(0, ulp_jumps_fail & UINT16_MAX);
|
||||
TEST_ASSERT_EQUAL(1, ulp_jumps_pass & UINT16_MAX);
|
||||
}
|
||||
101
components/ulp/test/ulp/test_jumps.S
Normal file
101
components/ulp/test/ulp/test_jumps.S
Normal file
@@ -0,0 +1,101 @@
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/soc_ulp.h"
|
||||
|
||||
.bss
|
||||
|
||||
.global jumps_pass
|
||||
jumps_pass:
|
||||
.long 0
|
||||
|
||||
.global jumps_fail
|
||||
jumps_fail:
|
||||
.long 0
|
||||
|
||||
.text
|
||||
.global test_jumps
|
||||
test_jumps:
|
||||
|
||||
/* tests for LT (less than) condition */
|
||||
stage_rst /* cnt = 0 */
|
||||
jumps test_fail, 0, LT /* 0 < 0: false, should not jump */
|
||||
jumps 1f, 1, LT /* 0 < 1: true, should jump */
|
||||
jump test_fail
|
||||
1:
|
||||
stage_inc 2 /* cnt = 2 */
|
||||
jumps 1f, 3, LT /* 2 < 1: true */
|
||||
jump test_fail
|
||||
1:
|
||||
jumps test_fail, 1, LT /* 2 < 1: false */
|
||||
jumps test_fail, 2, LT /* 2 < 2: false */
|
||||
|
||||
/* tests for LE (less or equal) condition */
|
||||
stage_rst /* cnt = 0 */
|
||||
jumps 1f, 0, LE /* 0 <= 0: true */
|
||||
jump test_fail
|
||||
1:
|
||||
jumps 1f, 1, LE /* 0 <= 1: true */
|
||||
jump test_fail
|
||||
1:
|
||||
stage_inc 2 /* cnt = 2 */
|
||||
jumps test_fail, 1, LE /* 2 <= 1: false */
|
||||
|
||||
/* tests for EQ (equal) condition */
|
||||
stage_rst /* cnt = 0 */
|
||||
jumps 1f, 0, EQ /* 0 = 0: true */
|
||||
jump test_fail
|
||||
1:
|
||||
jumps test_fail, 1, EQ /* 0 = 1: false */
|
||||
|
||||
stage_inc 1 /* cnt = 1 */
|
||||
jumps test_fail, 0, EQ /* 1 = 0: false */
|
||||
jumps test_fail, 2, EQ /* 1 = 2: false */
|
||||
jumps 1f, 1, EQ /* 1 = 1: true */
|
||||
1:
|
||||
|
||||
/* tests for GE (greater or equal) condition */
|
||||
stage_rst /* cnt = 0 */
|
||||
jumps 1f, 0, GE /* 0 >= 0: true */
|
||||
jump test_fail
|
||||
1:
|
||||
jumps test_fail, 1, GE /* 0 >= 1: false */
|
||||
|
||||
stage_inc 1 /* cnt = 1 */
|
||||
jumps 1f, 0, GE /* 1 >= 0: true */
|
||||
jump test_fail
|
||||
1:
|
||||
jumps 1f, 1, GE /* 1 >= 1: true */
|
||||
jump test_fail
|
||||
1:
|
||||
jumps test_fail, 2, GE /* 1 >= 2: false */
|
||||
|
||||
/* tests for GT (greater than) condition */
|
||||
stage_rst /* cnt = 0 */
|
||||
jumps test_fail, 0, GT /* 0 > 0: false */
|
||||
jumps test_fail, 1, GE /* 0 > 1: false */
|
||||
|
||||
stage_inc 1 /* cnt = 1 */
|
||||
jumps 1f, 0, GT /* 1 > 0: true */
|
||||
jump test_fail
|
||||
1:
|
||||
jumps test_fail, 1, GT /* 1 > 1: false */
|
||||
jumps test_fail, 2, GT /* 1 > 2: false */
|
||||
|
||||
jump test_pass
|
||||
|
||||
test_fail:
|
||||
move r0, jumps_fail
|
||||
move r1, 1
|
||||
st r1, r0, 0
|
||||
jump done
|
||||
|
||||
test_pass:
|
||||
move r0, jumps_pass
|
||||
move r1, 1
|
||||
st r1, r0, 0
|
||||
jump done
|
||||
|
||||
.global done
|
||||
done:
|
||||
wake
|
||||
halt
|
||||
@@ -1,6 +1,14 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# ************ IMPORTANT *****************
|
||||
#
|
||||
# ReadTheDocs DOES NOT USE THIS MAKEFILE,
|
||||
# so any behaviour additions must be
|
||||
# done via Sphinx Config not here
|
||||
#
|
||||
# ****************************************
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
@@ -9,7 +17,7 @@ BUILDDIR = _build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
@@ -19,10 +27,10 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) -w
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext dependencies version-specific-includes
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo "Please use \`make <target>\' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@@ -44,7 +52,7 @@ help:
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled) "
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
BIN
docs/_static/choose_version.png
vendored
Normal file
BIN
docs/_static/choose_version.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -15,8 +15,8 @@ Installing the toolchain
|
||||
|
||||
ULP coprocessor code is written in assembly and compiled using the `binutils-esp32ulp toolchain`_.
|
||||
|
||||
1. Download the toolchain using the links listed on this page:
|
||||
https://github.com/espressif/binutils-esp32ulp/wiki#downloads
|
||||
1. Download pre-built binaries of the latest toolchain release from:
|
||||
https://github.com/espressif/binutils-esp32ulp/releases.
|
||||
|
||||
2. Extract the toolchain into a directory, and add the path to the ``bin/`` directory of the toolchain to the ``PATH`` environment variable.
|
||||
|
||||
@@ -134,7 +134,7 @@ Each ULP program is embedded into the ESP-IDF application as a binary blob. Appl
|
||||
|
||||
Once the program is loaded into RTC memory, application can start it, passing the address of the entry point to ``ulp_run`` function::
|
||||
|
||||
ESP_ERROR_CHECK( ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)) );
|
||||
ESP_ERROR_CHECK( ulp_run(&ulp_entry - RTC_SLOW_MEM) );
|
||||
|
||||
.. doxygenfunction:: ulp_run
|
||||
|
||||
|
||||
1830
docs/api-guides/ulp_instruction_set.rst
Executable file → Normal file
1830
docs/api-guides/ulp_instruction_set.rst
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
15
docs/conf.py
15
docs/conf.py
@@ -32,6 +32,15 @@ os.system("python gen-dxd.py")
|
||||
# Generate 'kconfig.inc' file from components' Kconfig files
|
||||
os.system("python gen-kconfig-doc.py > _build/inc/kconfig.inc")
|
||||
|
||||
# Generate version-related includes
|
||||
#
|
||||
# (Note: this is in a function as it needs to access configuration to get the language)
|
||||
def generate_version_specific_includes(app):
|
||||
print("Generating version-specific includes...")
|
||||
if os.system('python gen-version-specific-includes.py en _build/inc'):
|
||||
raise RuntimeError('gen-version-specific-includes.py failed')
|
||||
|
||||
|
||||
# http://stackoverflow.com/questions/12772927/specifying-an-online-image-in-sphinx-restructuredtext-format
|
||||
#
|
||||
suppress_warnings = ['image.nonlocal_uri']
|
||||
@@ -314,3 +323,9 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
|
||||
# otherwise, readthedocs.org uses their theme by default, so no need to specify it
|
||||
|
||||
# Override RTD CSS theme to introduce the theme corrections
|
||||
# https://github.com/rtfd/sphinx_rtd_theme/pull/432
|
||||
def setup(app):
|
||||
app.add_stylesheet('theme_overrides.css')
|
||||
generate_version_specific_includes(app)
|
||||
|
||||
|
||||
140
docs/gen-version-specific-includes.py
Executable file
140
docs/gen-version-specific-includes.py
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Python script to generate ReSTructured Text .inc snippets
|
||||
# with version-based content for this IDF version
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
TEMPLATES = {
|
||||
"en" : {
|
||||
"git-clone" : {
|
||||
"template" : """
|
||||
To obtain a local copy: open terminal, navigate to the directory you want to put ESP-IDF, and clone the repository using ``git clone`` command::
|
||||
|
||||
cd ~/esp
|
||||
git clone %(clone_args)s--recursive https://github.com/espressif/esp-idf.git
|
||||
|
||||
ESP-IDF will be downloaded into ``~/esp/esp-idf``.
|
||||
|
||||
.. note::
|
||||
|
||||
%(extra_note)s
|
||||
|
||||
.. note::
|
||||
|
||||
%(zipfile_note)s
|
||||
"""
|
||||
,"master" : 'This command will clone the master branch, which has the latest development ("bleeding edge") version of ESP-IDF. It is fully functional and updated on weekly basis with the most recent features and bugfixes.'
|
||||
,"branch" : 'The ``git clone`` option ``-b %s`` tells git to clone the %s in the ESP-IDF repository corresponding to this version of the documentation.'
|
||||
,"zipfile" : {
|
||||
"stable" : 'As a fallback, it is also possible to download a zip file of this stable release from the `Releases page`_. Do not download the "Source code" zip file(s) generated automatically by GitHub, they do not work with ESP-IDF.'
|
||||
,"unstable" : 'GitHub\'s "Download zip file" feature does not work with ESP-IDF, a ``git clone`` is required. As a fallback, `Stable version`_ can be installed without Git.'
|
||||
}, # zipfile
|
||||
}, # git-clone
|
||||
"version-note" : {
|
||||
"master" : """
|
||||
.. note::
|
||||
This is documentation for the master branch (latest version) of ESP-IDF. This version is under continual development. `Stable version`_ documentation is available, as well as other :doc:`/versions`.
|
||||
"""
|
||||
,"stable" : """
|
||||
.. note::
|
||||
This is documentation for stable version %s of ESP-IDF. Other :doc:`/versions` are also available.
|
||||
"""
|
||||
,"branch" : """
|
||||
.. note::
|
||||
This is documentation for %s ``%s`` of ESP-IDF. Other :doc:`/versions` are also available.
|
||||
"""
|
||||
}, # version-note
|
||||
}, # en
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: gen-git-clone.py <language> <output file path>")
|
||||
sys.exit(1)
|
||||
|
||||
language = sys.argv[1]
|
||||
out_dir = sys.argv[2]
|
||||
if not os.path.exists(out_dir):
|
||||
print("Creating directory %s" % out_dir)
|
||||
os.mkdir(out_dir)
|
||||
|
||||
template = TEMPLATES[language]
|
||||
|
||||
version, ver_type, is_stable = get_version()
|
||||
|
||||
write_git_clone_inc(template["git-clone"], out_dir, version, ver_type, is_stable)
|
||||
write_version_note(template["version-note"], out_dir, version, ver_type, is_stable)
|
||||
print("Done")
|
||||
|
||||
|
||||
def write_git_clone_inc(template, out_dir, version, ver_type, is_stable):
|
||||
zipfile = template["zipfile"]
|
||||
if version == "master":
|
||||
args = {
|
||||
"clone_args" : "",
|
||||
"extra_note" : template["master"],
|
||||
"zipfile_note" : zipfile["unstable"]
|
||||
}
|
||||
else:
|
||||
args = {
|
||||
"clone_args" : "-b %s " % version,
|
||||
"extra_note" : template["branch"] % (version, ver_type),
|
||||
"zipfile_note" : zipfile["stable"] if is_stable else zipfile["unstable"]
|
||||
}
|
||||
out_file = os.path.join(out_dir, "git-clone.inc")
|
||||
with open(out_file, "w") as f:
|
||||
f.write(template["template"] % args)
|
||||
print("%s written" % out_file)
|
||||
|
||||
|
||||
def write_version_note(template, out_dir, version, ver_type, is_stable):
|
||||
if version == "master":
|
||||
content = template["master"]
|
||||
elif ver_type == "tag" and is_stable:
|
||||
content = template["stable"] % version
|
||||
else:
|
||||
content = template["branch"] % (ver_type, version)
|
||||
out_file = os.path.join(out_dir, "version-note.inc")
|
||||
with open(out_file, "w") as f:
|
||||
f.write(content)
|
||||
print("%s written" % out_file)
|
||||
|
||||
|
||||
def get_version():
|
||||
"""
|
||||
Returns a tuple of (name of branch/tag, type branch/tag, is_stable)
|
||||
"""
|
||||
# Trust what RTD says our version is, if it is set
|
||||
version = os.environ.get("READTHEDOCS_VERSION", None)
|
||||
if version == "latest":
|
||||
return ("master", "branch", False)
|
||||
|
||||
# Otherwise, use git to look for a tag
|
||||
try:
|
||||
tag = subprocess.check_output(["git", "describe", "--tags", "--exact-match"]).strip()
|
||||
is_stable = re.match(r"v[0-9\.]+$", tag) is not None
|
||||
return (tag, "tag", is_stable)
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
|
||||
# No tag, look for a branch
|
||||
refs = subprocess.check_output(["git", "for-each-ref", "--points-at", "HEAD", "--format", "%(refname)"])
|
||||
print("refs:\n%s" % refs)
|
||||
refs = refs.split("\n")
|
||||
# Note: this looks for branches in 'origin' because GitLab CI doesn't check out a local branch
|
||||
branches = [ r.replace("refs/remotes/origin/","").strip() for r in refs if r.startswith("refs/remotes/origin/") ]
|
||||
if len(branches) == 0:
|
||||
# last resort, return the commit (may happen on Gitlab CI sometimes, unclear why)
|
||||
return (subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).strip(), "commit", False)
|
||||
if "master" in branches:
|
||||
return ("master", "branch", False)
|
||||
else:
|
||||
return (branches[0], "branch", False) # take whatever the first branch is
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -42,7 +42,7 @@ Project Properties
|
||||
|
||||
* Click on the "C/C++ Build" properties page (top-level):
|
||||
|
||||
* Uncheck "Use default build command" and enter this for the custom build command: ``python ${IDF_PATH}/tools/windows/eclipse_make.py``.
|
||||
* Uncheck "Use default build command" and enter this for the custom build command: ``python ${IDF_PATH}/tools/windows/eclipse_make.py``
|
||||
|
||||
* Click on the "Environment" properties page under "C/C++ Build":
|
||||
|
||||
@@ -56,10 +56,15 @@ Project Properties
|
||||
|
||||
* Click the "Providers" tab
|
||||
|
||||
* In the list of providers, click "CDT GCC Built-in Compiler Settings Cygwin". Under "Command to get compiler specs", replace the text ``${COMMAND}`` at the beginning of the line with ``xtensa-esp32-elf-gcc``. This means the full "Command to get compiler specs" should be ``xtensa-esp32-elf-gcc ${FLAGS} -E -P -v -dD "${INPUTS}"``.
|
||||
* In the list of providers, click "CDT Cross GCC Built-in Compiler Settings". Change "Command to get compiler specs" to ``xtensa-esp32-elf-gcc ${FLAGS} -E -P -v -dD "${INPUTS}"``.
|
||||
|
||||
* In the list of providers, click "CDT GCC Build Output Parser" and type ``xtensa-esp32-elf-`` at the beginning of the Compiler command pattern, and wrap remaining part with brackets. This means the full Compiler command pattern should be ``xtensa-esp32-elf-((g?cc)|([gc]\+\+)|(clang))``
|
||||
* In the list of providers, click "CDT GCC Build Output Parser" and change the "Compiler command pattern" to ``xtensa-esp32-elf-(gcc|g\+\+|c\+\+|cc|cpp|clang)``
|
||||
|
||||
Navigate to "C/C++ General" -> "Indexer" property page:
|
||||
|
||||
* Check "Enable project specific settings" to enable the rest of the settings on this page.
|
||||
|
||||
* Uncheck "Allow heuristic resolution of includes". When this option is enabled Eclipse sometimes fails to find correct header directories.
|
||||
|
||||
Building in Eclipse
|
||||
-------------------
|
||||
|
||||
@@ -58,9 +58,15 @@ Navigate to "C/C++ General" -> "Preprocessor Include Paths" property page:
|
||||
|
||||
* Click the "Providers" tab
|
||||
|
||||
* In the list of providers, click "CDT Cross GCC Built-in Compiler Settings". Under "Command to get compiler specs", replace the text ``${COMMAND}`` at the beginning of the line with ``xtensa-esp32-elf-gcc``. This means the full "Command to get compiler specs" should be ``xtensa-esp32-elf-gcc ${FLAGS} -E -P -v -dD "${INPUTS}"``.
|
||||
* In the list of providers, click "CDT Cross GCC Built-in Compiler Settings". Change "Command to get compiler specs" to ``xtensa-esp32-elf-gcc ${FLAGS} -E -P -v -dD "${INPUTS}"``.
|
||||
|
||||
* In the list of providers, click "CDT GCC Build Output Parser" and type ``xtensa-esp32-elf-`` at the beginning of the Compiler command pattern. This means the full Compiler command pattern should be ``xtensa-esp32-elf-(g?cc)|([gc]\+\+)|(clang)``
|
||||
* In the list of providers, click "CDT GCC Build Output Parser" and change the "Compiler command pattern" to ``xtensa-esp32-elf-(gcc|g\+\+|c\+\+|cc|cpp|clang)``
|
||||
|
||||
Navigate to "C/C++ General" -> "Indexer" property page:
|
||||
|
||||
* Check "Enable project specific settings" to enable the rest of the settings on this page.
|
||||
|
||||
* Uncheck "Allow heuristic resolution of includes". When this option is enabled Eclipse sometimes fails to find correct header directories.
|
||||
|
||||
.. _eclipse-build-project:
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ Get Started
|
||||
|
||||
This document is intended to help users set up the software environment for developement of applications using hardware based on the Espressif ESP32. Through a simple example we would like to illustrate how to use ESP-IDF (Espressif IoT Development Framework), including the menu based configuration, compiling the ESP-IDF and firmware download to ESP32 boards.
|
||||
|
||||
.. include:: /_build/inc/version-note.inc
|
||||
|
||||
Introduction
|
||||
============
|
||||
@@ -113,19 +114,18 @@ Get ESP-IDF
|
||||
|
||||
.. highlight:: bash
|
||||
|
||||
Besides the toolchain (that contains programs to compile and build the application), you also need ESP32 specific API / libraries. They are provided by Espressif in `ESP-IDF repository <https://github.com/espressif/esp-idf>`_. To get it, open terminal, navigate to the directory you want to put ESP-IDF, and clone it using ``git clone`` command::
|
||||
Besides the toolchain (that contains programs to compile and build the application), you also need ESP32 specific API / libraries. They are provided by Espressif in `ESP-IDF repository <https://github.com/espressif/esp-idf>`_.
|
||||
|
||||
cd ~/esp
|
||||
git clone --recursive https://github.com/espressif/esp-idf.git
|
||||
.. include:: /_build/inc/git-clone.inc
|
||||
|
||||
ESP-IDF will be downloaded into ``~/esp/esp-idf``.
|
||||
Consult :doc:`/versions` for information about which version of ESP-IDF to use in a given situation.
|
||||
|
||||
.. note::
|
||||
|
||||
Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules::
|
||||
|
||||
cd ~/esp/esp-idf
|
||||
git submodule update --init
|
||||
git submodule update --init --recursive
|
||||
|
||||
|
||||
.. _get-started-setup-path:
|
||||
@@ -299,23 +299,9 @@ Updating ESP-IDF
|
||||
|
||||
After some time of using ESP-IDF, you may want to update it to take advantage of new features or bug fixes. The simplest way to do so is by deleting existing ``esp-idf`` folder and cloning it again, exactly as when doing initial installation described in sections :ref:`get-started-get-esp-idf`.
|
||||
|
||||
Another solution is to update only what has changed. This method is useful if you have slow connection to the GiHub. To do the update run the following commands::
|
||||
If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts know where to find the ESP-IDF in its release specific location.
|
||||
|
||||
cd ~/esp/esp-idf
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
|
||||
The ``git pull`` command is fetching and merging changes from ESP-IDF repository on GitHub. Then ``git submodule update --init --recursive`` is updating existing submodules or getting a fresh copy of new ones. On GitHub the submodules are represented as links to other repositories and require this additional command to get them onto your PC.
|
||||
|
||||
If you would like to use specific release of ESP-IDF, e.g. `v2.1`, run::
|
||||
|
||||
cd ~/esp
|
||||
git clone https://github.com/espressif/esp-idf.git esp-idf-v2.1
|
||||
cd esp-idf-v2.1/
|
||||
git checkout v2.1
|
||||
git submodule update --init --recursive
|
||||
|
||||
After that remember to :doc:`add-idf_path-to-profile`, so the toolchain scripts know where to find the ESP-IDF in it's release specific location.
|
||||
Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using <updating>`.
|
||||
|
||||
|
||||
Related Documents
|
||||
@@ -330,3 +316,7 @@ Related Documents
|
||||
eclipse-setup
|
||||
idf-monitor
|
||||
toolchain-setup-scratch
|
||||
|
||||
.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/
|
||||
.. _Releases page: https://github.com/espressif/esp-idf/releases
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ This is the documentation for Espressif IoT Development Framework (`esp-idf <htt
|
||||
H/W Reference <hw-reference/index>
|
||||
API Guides <api-guides/index>
|
||||
Contribute <contribute/index>
|
||||
Versions <versions>
|
||||
Resources <resources>
|
||||
Copyrights <COPYRIGHT>
|
||||
About <about>
|
||||
|
||||
@@ -6,9 +6,9 @@ from repo_util import run_cmd_get_output
|
||||
def get_github_rev():
|
||||
path = run_cmd_get_output('git rev-parse --short HEAD')
|
||||
tag = run_cmd_get_output('git describe --exact-match')
|
||||
print 'Git commit ID: ', path
|
||||
print ('Git commit ID: ', path)
|
||||
if len(tag):
|
||||
print 'Git tag: ', tag
|
||||
print ('Git tag: ', tag)
|
||||
path = tag
|
||||
return path
|
||||
|
||||
|
||||
178
docs/versions.rst
Normal file
178
docs/versions.rst
Normal file
@@ -0,0 +1,178 @@
|
||||
ESP-IDF Versions
|
||||
================
|
||||
|
||||
The ESP-IDF GitHub repository is updated regularly, especially on the "master branch" where new development happens. There are also stable releases which are recommended for production use.
|
||||
|
||||
Releases
|
||||
--------
|
||||
|
||||
Documentation for the current stable version can always be found at this URL:
|
||||
|
||||
https://docs.espressif.com/projects/esp-idf/en/stable/
|
||||
|
||||
Documentation for the latest version ("master branch") can always be found at this URL:
|
||||
|
||||
https://docs.espressif.com/projects/esp-idf/en/latest/
|
||||
|
||||
The full history of releases can be found on the GitHub repository `Releases page`_. There you can find release notes, links to each version of the documentation, and instructions for obtaining each version.
|
||||
|
||||
Documentation for all releases can also be found in the HTML documentation by clicking the "versions" pop up in the bottom-left corner of the page. You can use this popup to switch between versions of the documentation.
|
||||
|
||||
.. image:: _static/choose_version.png
|
||||
|
||||
Which Version Should I Start With?
|
||||
----------------------------------
|
||||
|
||||
- For production purposes, use the `current stable version`_. Stable versions have been manually tested, and are updated with "bugfix releases" which fix bugs without changing other functionality (see `Versioning Scheme`_ for more details).
|
||||
|
||||
- For prototyping, experimentation or for developing new ESP-IDF features, use the `latest version (master branch in Git) <https://docs.espressif.com/projects/esp-idf/en/latest/>`_. The latest version in the master branch has all the latest features and has passed automated testing, but has not been completely manually tested ("bleeding edge").
|
||||
|
||||
- If a required feature is not yet available in a stable release, but you don't want to use the master branch, it is possible to check out a pre-release version or a release branch. It is recommended to start from a stable version and then follow the instructions for :ref:`updating-pre-release` or :ref:`updating-release-branch`.
|
||||
|
||||
See :ref:`updating` if you already have a local copy of ESP-IDF and wish to update it.
|
||||
|
||||
Versioning Scheme
|
||||
-----------------
|
||||
|
||||
ESP-IDF uses `Semantic Versioning <http://semver.org/>`_. This means:
|
||||
|
||||
- Major Releases like ``v3.0`` add new functionality and may change functionality. This includes removing deprecated functionality.
|
||||
|
||||
When updating to a new major release (for example, from ``v2.1`` to ``v3.0``), some of your project's code may need updating and functionality will need to be re-tested. The release notes on the `Releases page`_ include lists of Breaking Changes to refer to.
|
||||
- Minor Releases like ``v3.1`` add new functionality and fix bugs but will not change or remove documented functionality, or make incompatible changes to public APIs.
|
||||
|
||||
If updating to a new minor release (for example, from ``v3.0`` to ``v3.1``) then none of your project's code should need updating, but you should re-test your project. Pay particular attention to items mentioned in the release notes on the `Releases page`_.
|
||||
- Bugfix Releases like ``v3.0.1`` only fix bugs and do not add new functionality.
|
||||
|
||||
If updating to a new bugfix release (for example, from ``v3.0`` to ``v3.0.1``), you should not need to change any code in your project and should only need to re-test functionality relating directly to bugs listed in the release notes on the `Releases page`_.
|
||||
|
||||
Checking The Current Version
|
||||
----------------------------
|
||||
|
||||
The local ESP-IDF version can be checked using git::
|
||||
|
||||
cd $IDF_PATH
|
||||
git describe --tags --dirty
|
||||
|
||||
The version is also compiled into the firmware and can be accessed (as a string) via the macro ``IDF_VER``. The default ESP-IDF bootloader will print the version on boot (these versions in code will not always update, it only changes if that particular source file is recompiled).
|
||||
|
||||
Examples of ESP-IDF versions:
|
||||
|
||||
============================ ==================================================
|
||||
Version String Meaning
|
||||
============================ ==================================================
|
||||
``v3.2-dev-306-gbeb3611ca`` Master branch pre-release, in development for
|
||||
version 3.2. 306 commits after v3.2 development
|
||||
started. Commit identifier ``beb3611ca``.
|
||||
``v3.0.2`` Stable release, tagged ``v3.0.2``.
|
||||
``v3.1-beta1-75-g346d6b0ea`` Beta version in development (on a
|
||||
:ref:`release branch <updating-release-branch>`).
|
||||
75 commits after ``v3.1-beta1`` pre-release tag.
|
||||
Commit identifier ``346d6b0ea``.
|
||||
``v3.0.1-dirty`` Stable release, tagged ``v3.0.1``.
|
||||
There are modifications in the local ESP-IDF
|
||||
directory ("``dirty``").
|
||||
============================ ==================================================
|
||||
|
||||
|
||||
|
||||
Git Workflow
|
||||
------------
|
||||
|
||||
The development (Git) workflow of the Espressif ESP-IDF team is:
|
||||
|
||||
- New work is always added on the master branch (latest version) first. The ESP-IDF version on ``master`` is always tagged with ``-dev`` (for "in development"), for example ``v3.1-dev``.
|
||||
- Changes are first added to an internal Git repository for code review and testing, but are pushed to GitHub after automated testing passes.
|
||||
- When a new version (developed on ``master``) becomes feature complete and "beta" quality, a new branch is made for the release, for example ``release/v3.1``. A pre-release tag is also created, for example ``v3.1-beta1``. You can see a full `list of branches`_ and a `list of tags`_ on GitHub. Beta pre-releases have release notes which may include a significant number of Known Issues.
|
||||
- As testing of the beta version progresses, bug fixes will be added to both the ``master`` branch and the release branch. New features (for the next release) may start being added to ``master`` at the same time.
|
||||
- Once testing is nearly complete a new release candidate is tagged on the release branch, for example ``v3.1-rc1``. This is still a pre-release version.
|
||||
- If no more significant bugs are found or reported then the final Major or Minor Version is tagged, for example ``v3.1``. This version appears on the `Releases page`_.
|
||||
- As bugs are reported in released versions, the fixes will continue to be committed to the same release branch.
|
||||
- Regular bugfix releases are made from the same release branch. After manual testing is complete, a bugfix release is tagged (i.e. ``v3.1.1``) and appears on the `Releases page`_.
|
||||
|
||||
.. _updating:
|
||||
|
||||
Updating ESP-IDF
|
||||
----------------
|
||||
|
||||
Updating ESP-IDF depends on which version(s) you wish to follow:
|
||||
|
||||
- :ref:`updating-stable-releases` is recommended for production use.
|
||||
- :ref:`updating-master` is recommended for latest features, development use, and testing.
|
||||
- :ref:`updating-release-branch` is a compromise between these two.
|
||||
|
||||
.. note:: These guides assume you already have a local copy of ESP-IDF. To get one, follow the :doc:`Getting Started </get-started/index>` guide for any ESP-IDF version.
|
||||
|
||||
.. _`updating-stable-releases`:
|
||||
|
||||
Updating to Stable Release
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To update to new ESP-IDF releases (recommended for production use), this is the process to follow:
|
||||
|
||||
- Check the `Releases page`_ regularly for new releases.
|
||||
- When a bugfix release for a version you are using is released (for example if using ``v3.0.1`` and ``v3.0.2`` is available), check out the new bugfix version into the existing ESP-IDF directory::
|
||||
|
||||
cd $IDF_PATH
|
||||
git fetch
|
||||
git checkout vX.Y.Z
|
||||
git submodule update --init --recursive
|
||||
- When major or minor updates are released, check the Release Notes on the releases page and decide if you would like to update or to stay with your existing release. Updating is via the same Git commands shown above.
|
||||
|
||||
.. note:: If you installed the stable release via zip file rather than using git, it may not be possible to change versions this way. In this case, update by downloading a new zip file and replacing the entire ``IDF_PATH`` directory with its contents.
|
||||
|
||||
|
||||
.. _`updating-pre-release`:
|
||||
|
||||
Updating to a Pre-Release Version
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
It is also possible to ``git checkout`` a tag corresponding to a pre-release version or release candidate, the process is the same as :ref:`updating-stable-releases`.
|
||||
|
||||
Pre-release tags are not always found on the `Releases page`_. Consult the `list of tags`_ on GitHub for a full list. Caveats for using a pre-release are similar to :ref:`updating-release-branch`.
|
||||
|
||||
.. _`updating-master`:
|
||||
|
||||
Updating to Master Branch
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. note:: Using Master branch means living "on the bleeding edge" with the latest ESP-IDF code.
|
||||
|
||||
To use the latest version on the ESP-IDF master branch, this is the process to follow:
|
||||
|
||||
- Check out the master branch locally::
|
||||
|
||||
cd $IDF_PATH
|
||||
git checkout master
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
- Periodically, re-run ``git pull`` to pull the latest version of master. Note that you may need to change your project or report bugs after updating master branch.
|
||||
- To switch from ``master`` to a release branch or stable version, run ``git checkout`` as shown in the other sections.
|
||||
|
||||
.. important:: It is strongly recommended to regularly run ``git pull`` and then ``git submodule update --init --recursive`` so a local copy of ``master`` does not get too old. Arbitrary old master branch revisions are effectively unsupportable "snapshots" that may have undocumented bugs. For a semi-stable version, try :ref:`updating-release-branch` instead.
|
||||
|
||||
.. _`updating-release-branch`:
|
||||
|
||||
Updating to a Release Branch
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In stability terms, using a release branch is part-way between using ``master`` branch and only using stable releases. A release branch is always beta quality or better, and receives bug fixes before they appear in each stable release.
|
||||
|
||||
You can find a `list of branches`_ on GitHub.
|
||||
|
||||
For example, to follow the branch for ESP-IDF v3.1, including any bugfixes for future releases like ``v3.1.1``, etc::
|
||||
|
||||
cd $IDF_PATH
|
||||
git fetch
|
||||
git checkout release/v3.1
|
||||
git pull
|
||||
git submodule --update --init --recursive
|
||||
|
||||
Each time you ``git pull`` this branch, ESP-IDF will be updated with fixes for this release.
|
||||
|
||||
.. note:: The is no dedicated documentation for release branches. It is recommended to use the documentation for the closest version to the branch which is currently checked out.
|
||||
|
||||
.. _`Releases page`: http://github.com/espressif/esp-idf/releases
|
||||
.. _`list of branches`: https://github.com/espressif/esp-idf/branches
|
||||
.. _`list of tags`: https://github.com/espressif/esp-idf/tags
|
||||
.. _`current stable version`: https://docs.espressif.com/projects/esp-idf/en/stable/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user