forked from espressif/esp-idf
Compare commits
290 Commits
fixes
...
v3.2-beta3
Author | SHA1 | Date | |
---|---|---|---|
91aa35e831 | |||
113e829552 | |||
3802fddefb | |||
bb2eb9adeb | |||
78116afa01 | |||
b865e72aec | |||
f1b2457b6c | |||
46fa5654a7 | |||
bf28a1a27b | |||
b7beefba9e | |||
0784c52131 | |||
a7f826750b | |||
38086ae737 | |||
6173660ff0 | |||
79b450cfb4 | |||
c7fbc6dd85 | |||
3b5bba1812 | |||
b4feb67b5f | |||
578d7902af | |||
509884c5ac | |||
8a656f006e | |||
0f79c72704 | |||
6d6f71bbae | |||
332ccd0925 | |||
2ee1c6fd3e | |||
6a328992d7 | |||
b51f109dd7 | |||
85e8dea26a | |||
093c7b176d | |||
30e39631db | |||
a7ff611b10 | |||
2e64d2d56e | |||
3e6b402756 | |||
5568ca2855 | |||
30f2371917 | |||
ebaa944a9a | |||
d83598a64a | |||
00d1068869 | |||
49be9fb836 | |||
6f0c70daf6 | |||
219c85cf60 | |||
524696d59a | |||
9a229f4077 | |||
016c8d8b05 | |||
9914b839aa | |||
76e4ea7f68 | |||
3ec0f415a5 | |||
fa40b3d5d0 | |||
f742808333 | |||
51bd64c754 | |||
b85321be97 | |||
dcd63f73f6 | |||
b8f0c32a0a | |||
8f2e1471af | |||
a159e58ead | |||
fe767855df | |||
1e674fb4ed | |||
3660ccac4c | |||
4f9a4e8ed7 | |||
582bf18789 | |||
2e3f06ece8 | |||
c62a20f162 | |||
ed4d83af8e | |||
1444868917 | |||
05ba4f15d6 | |||
37b7153c0e | |||
1a53334843 | |||
fd29b0165f | |||
9c3262f80b | |||
900dbfd1f6 | |||
13a1f4ed78 | |||
8a69ffc36f | |||
a437e4dc5c | |||
741f97da4e | |||
eae2baa0f1 | |||
f49f5ff35a | |||
020b295f06 | |||
6e14de0fa8 | |||
95c7f45e84 | |||
651a08f710 | |||
18cb87b4ce | |||
1fedece94d | |||
137810915c | |||
bb766355b5 | |||
807ef53c38 | |||
e585121011 | |||
671be20cc5 | |||
022a9295b0 | |||
a34d788a5e | |||
2a47c5c7a4 | |||
cfc4f74b52 | |||
43a722f0de | |||
eff24857bc | |||
18118a6d5c | |||
64757c0228 | |||
bab80ad202 | |||
76f0dda3a4 | |||
ce9878ce71 | |||
403a24ab64 | |||
d2cf266762 | |||
cec39b750a | |||
0420f290a4 | |||
eb6dbeb15a | |||
5c9ab21d81 | |||
bab379faf8 | |||
fb7cd2a7a7 | |||
c208a6b451 | |||
78511c3cc3 | |||
cd6bbaa727 | |||
55b8f2ea8c | |||
ec2f1a6b9a | |||
26646b5b31 | |||
1ae9a2ae0b | |||
28eb488892 | |||
fcf1dba9cd | |||
94ed7b8298 | |||
24fab0b7a9 | |||
c4c1af114e | |||
b1ee25afde | |||
cccaa68467 | |||
6080767379 | |||
42b6c4953d | |||
746e831c19 | |||
36f9091e03 | |||
553ba51924 | |||
929d98538e | |||
b810b32675 | |||
00bf376bc3 | |||
fe19ea977b | |||
a953f73c64 | |||
bed50a93f0 | |||
a80bfc1dcf | |||
51d846417e | |||
ca54a5ce2a | |||
7b1777dd30 | |||
64b46ff1d9 | |||
c355d8a88e | |||
977af32d0f | |||
f0a6432717 | |||
c18e86a826 | |||
b5d53a0eff | |||
10afc3de77 | |||
545878d4e9 | |||
ec7909956d | |||
d9c3a08813 | |||
eb9a93f9b7 | |||
710019a47f | |||
2d27358f61 | |||
b80eba8d5a | |||
7832db7bb3 | |||
efa70bc8e3 | |||
31b7db5c38 | |||
8d02ccd2f7 | |||
62eb0f4c12 | |||
155f034b1e | |||
47dea73b03 | |||
28fdf96828 | |||
3969fe0dad | |||
c70c25afd0 | |||
d59d9eef4f | |||
22514e12d8 | |||
f48ffb37f2 | |||
0f041ee7bb | |||
c320a3ee4c | |||
1f35716ef4 | |||
358de85eb3 | |||
84277e5887 | |||
52a70e0489 | |||
6523d912f2 | |||
aa0d2078b7 | |||
348d6d5d3f | |||
46228db9a8 | |||
2cac11f162 | |||
64eeee4532 | |||
a9eb37e2c8 | |||
c7a297195f | |||
19e96add8a | |||
a0a0328e4f | |||
04aebc464c | |||
30e01847ad | |||
3f6033d8bd | |||
45e59a9f56 | |||
587e6ec93f | |||
6d00c7fc49 | |||
c418714ec6 | |||
19d8c050cd | |||
cb650382ca | |||
e5e592e5b6 | |||
28e20e90e3 | |||
1c4d9f2aca | |||
ded8b0102a | |||
401970495d | |||
5d46bb596d | |||
8de9149b11 | |||
e8b8946e6e | |||
2c1e3d1ef2 | |||
bf608b6709 | |||
24ebdbd3f4 | |||
fd00d3213b | |||
c921a5bc4b | |||
ade85cc850 | |||
5c8d25b795 | |||
ac051f0afc | |||
bb47146710 | |||
07cb228f64 | |||
3cfe1c89b5 | |||
4f805d558c | |||
f53716d851 | |||
f8fd922ca5 | |||
61d07ffbfc | |||
6b5649190f | |||
f44507de53 | |||
88c7a61a63 | |||
6af90457f7 | |||
3aafb2cfcf | |||
8ec0c82c3f | |||
a338c1b712 | |||
0b21be508e | |||
3b4d51bbfa | |||
60c556eb55 | |||
9933e37c8b | |||
67bdc8aaf4 | |||
44bd6f72bc | |||
2d67ce3109 | |||
e85cb6d148 | |||
7658b8ab62 | |||
7969a566e3 | |||
be05b1e654 | |||
ca51b60033 | |||
9b3ff1bed0 | |||
f859f9e25b | |||
f2ae151dab | |||
bae0d8a313 | |||
cfcc0edc33 | |||
54e6f0793a | |||
e98f4d2751 | |||
33cf0faac8 | |||
7385e71c84 | |||
7778ce83bd | |||
0f8070a6fd | |||
0fcb9056f8 | |||
5110d4b303 | |||
fc19954376 | |||
16d32c58e7 | |||
3d926da642 | |||
9bb719dd68 | |||
536cb0489e | |||
98c7cb5560 | |||
4baf333c79 | |||
79401934a1 | |||
ec1daf32e1 | |||
1cac0d2cf2 | |||
8d1594c339 | |||
a0f516de0b | |||
802d94aa35 | |||
3c3e375d8d | |||
d57ea422be | |||
3b3242cbae | |||
96c2b34eb9 | |||
6b3a8acdc3 | |||
a10abd695b | |||
0f28a51996 | |||
6681096e55 | |||
18b65dca26 | |||
a398116b1c | |||
331c7c7dc3 | |||
7bd9559e7e | |||
e84289077c | |||
c59c40741b | |||
f3c1903791 | |||
2885ec3831 | |||
a7db0e2291 | |||
cb98f5a814 | |||
8725bce5bc | |||
174b3b89e4 | |||
8d9d8e27ca | |||
93f4dc6b32 | |||
b021bbdc80 | |||
c9fe4fa13e | |||
96252c493a | |||
007a4fcc4e | |||
dbeb8ae02a | |||
9921c8b91f | |||
e16f65f4e6 | |||
fe0a5b41bf | |||
1f7c54ae85 | |||
049bd9fe0a | |||
167fb50a22 | |||
5f3b532c8d | |||
841a6dcd9a |
129
.gitlab-ci.yml
129
.gitlab-ci.yml
@ -2,8 +2,7 @@ stages:
|
||||
- build
|
||||
- assign_test
|
||||
- host_test
|
||||
- unit_test
|
||||
- integration_test
|
||||
- target_test
|
||||
- check
|
||||
- deploy
|
||||
- post_check
|
||||
@ -114,19 +113,21 @@ build_template_app:
|
||||
- build
|
||||
variables:
|
||||
BATCH_BUILD: "1"
|
||||
IDF_CI_BUILD: "1"
|
||||
only:
|
||||
variables:
|
||||
- $BOT_TRIGGER_WITH_LABEL == null
|
||||
- $BOT_LABEL_BUILD
|
||||
- $BOT_LABEL_REGULAR_TEST
|
||||
script:
|
||||
- git clone https://github.com/espressif/esp-idf-template.git
|
||||
# Set the variable for 'esp-idf-template' testing
|
||||
- ESP_IDF_TEMPLATE_GIT=${ESP_IDF_TEMPLATE_GIT:-"https://github.com/espressif/esp-idf-template.git"}
|
||||
- git clone ${ESP_IDF_TEMPLATE_GIT}
|
||||
- cd esp-idf-template
|
||||
# Try to use the same branch name for esp-idf-template that we're
|
||||
# using on esp-idf. If it doesn't exist then just stick to the default
|
||||
# branch
|
||||
- python $CHECKOUT_REF_SCRIPT esp-idf-template
|
||||
- make defconfig
|
||||
# Test debug build (default)
|
||||
- make all V=1
|
||||
# Now test release build
|
||||
@ -180,13 +181,13 @@ build_ssc_02:
|
||||
|
||||
# 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_esp_idf_unit_test_template: &build_esp_idf_unit_test_template
|
||||
<<: *build_template
|
||||
artifacts:
|
||||
paths:
|
||||
- tools/unit-test-app/output
|
||||
- components/idf_test/unit_test/TestCaseAll.yml
|
||||
- components/idf_test/unit_test/CIConfigs/*.yml
|
||||
expire_in: 2 days
|
||||
only:
|
||||
variables:
|
||||
@ -194,11 +195,30 @@ build_esp_idf_tests:
|
||||
- $BOT_LABEL_BUILD
|
||||
- $BOT_LABEL_UNIT_TEST
|
||||
- $BOT_LABEL_REGULAR_TEST
|
||||
|
||||
build_esp_idf_tests_make:
|
||||
<<: *build_esp_idf_unit_test_template
|
||||
script:
|
||||
- export PATH="$IDF_PATH/tools:$PATH"
|
||||
- cd $CI_PROJECT_DIR/tools/unit-test-app
|
||||
- export EXTRA_CFLAGS="-Werror -Werror=deprecated-declarations"
|
||||
- export EXTRA_CXXFLAGS=${EXTRA_CFLAGS}
|
||||
- cd $CI_PROJECT_DIR/tools/unit-test-app
|
||||
- MAKEFLAGS= make help # make sure kconfig tools are built in single process
|
||||
- make ut-clean-all-configs
|
||||
- make ut-build-all-configs
|
||||
- python tools/UnitTestParser.py
|
||||
- if [ "$UNIT_TEST_BUILD_SYSTEM" == "make" ]; then exit 0; fi
|
||||
# If Make, delete the CMake built artifacts
|
||||
- rm -rf builds output sdkconfig
|
||||
- rm -rf $CI_PROJECT_DIR/components/idf_test/unit_test/TestCaseAll.yml
|
||||
- rm -rf $CI_PROJECT_DIR/components/idf_test/unit_test/CIConfigs/*.yml
|
||||
|
||||
build_esp_idf_tests_cmake:
|
||||
<<: *build_esp_idf_unit_test_template
|
||||
script:
|
||||
- export PATH="$IDF_PATH/tools:$PATH"
|
||||
- export EXTRA_CFLAGS="-Werror -Werror=deprecated-declarations"
|
||||
- export EXTRA_CXXFLAGS=${EXTRA_CFLAGS}
|
||||
- cd $CI_PROJECT_DIR/tools/unit-test-app
|
||||
# Build with CMake first
|
||||
- idf.py ut-clean-all-configs
|
||||
- idf.py ut-build-all-configs
|
||||
@ -207,14 +227,8 @@ build_esp_idf_tests:
|
||||
- if [ "$UNIT_TEST_BUILD_SYSTEM" == "cmake" ]; then exit 0; fi
|
||||
# If Make, delete the CMake built artifacts
|
||||
- rm -rf builds output sdkconfig
|
||||
- rm -rf components/idf_test/unit_test/TestCaseAll.yml
|
||||
- rm -rf components/idf_test/unit_test/CIConfigs/*.yml
|
||||
# Then build with Make
|
||||
- cd $CI_PROJECT_DIR/tools/unit-test-app
|
||||
- MAKEFLAGS= make help # make sure kconfig tools are built in single process
|
||||
- make ut-clean-all-configs
|
||||
- make ut-build-all-configs
|
||||
- python tools/UnitTestParser.py
|
||||
- rm -rf $CI_PROJECT_DIR/components/idf_test/unit_test/TestCaseAll.yml
|
||||
- rm -rf $CI_PROJECT_DIR/components/idf_test/unit_test/CIConfigs/*.yml
|
||||
|
||||
.build_examples_make_template: &build_examples_make_template
|
||||
<<: *build_template
|
||||
@ -225,6 +239,7 @@ build_esp_idf_tests:
|
||||
when: always
|
||||
paths:
|
||||
- build_examples/*/*/*/build/*.bin
|
||||
- build_examples/*/*/*/sdkconfig
|
||||
- build_examples/*/*/*/build/*.elf
|
||||
- build_examples/*/*/*/build/*.map
|
||||
- build_examples/*/*/*/build/download.config
|
||||
@ -232,7 +247,6 @@ build_esp_idf_tests:
|
||||
- $LOG_PATH
|
||||
expire_in: 2 days
|
||||
variables:
|
||||
IDF_CI_BUILD: "1"
|
||||
LOG_PATH: "$CI_PROJECT_DIR/log_examples_make"
|
||||
only:
|
||||
variables:
|
||||
@ -257,6 +271,7 @@ build_esp_idf_tests:
|
||||
when: always
|
||||
paths:
|
||||
- build_examples_cmake/*/*/*/build/*.bin
|
||||
- build_examples_cmake/*/*/*/sdkconfig
|
||||
- build_examples_cmake/*/*/*/build/*.elf
|
||||
- build_examples_cmake/*/*/*/build/*.map
|
||||
- build_examples_cmake/*/*/*/build/download.config
|
||||
@ -264,7 +279,6 @@ build_esp_idf_tests:
|
||||
- $LOG_PATH
|
||||
expire_in: 2 days
|
||||
variables:
|
||||
IDF_CI_BUILD: "1"
|
||||
LOG_PATH: "$CI_PROJECT_DIR/log_examples_cmake"
|
||||
only:
|
||||
variables:
|
||||
@ -749,7 +763,8 @@ assign_test:
|
||||
- build_ssc_00
|
||||
- build_ssc_01
|
||||
- build_ssc_02
|
||||
- build_esp_idf_tests
|
||||
- build_esp_idf_tests_make
|
||||
- build_esp_idf_tests_cmake
|
||||
variables:
|
||||
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
|
||||
EXAMPLE_CONFIG_OUTPUT_PATH: "$CI_PROJECT_DIR/examples/test_configs"
|
||||
@ -779,7 +794,7 @@ 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: integration_test
|
||||
stage: target_test
|
||||
when: on_success
|
||||
only:
|
||||
refs:
|
||||
@ -814,6 +829,8 @@ assign_test:
|
||||
paths:
|
||||
- $LOG_PATH
|
||||
expire_in: 1 week
|
||||
reports:
|
||||
junit: $LOG_PATH/*/XUNIT_RESULT.xml
|
||||
variables:
|
||||
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
|
||||
TEST_CASE_PATH: "$CI_PROJECT_DIR/examples"
|
||||
@ -833,10 +850,11 @@ assign_test:
|
||||
|
||||
.unit_test_template: &unit_test_template
|
||||
<<: *example_test_template
|
||||
stage: unit_test
|
||||
stage: target_test
|
||||
dependencies:
|
||||
- assign_test
|
||||
- build_esp_idf_tests
|
||||
- build_esp_idf_tests_make
|
||||
- build_esp_idf_tests_cmake
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
@ -855,7 +873,7 @@ assign_test:
|
||||
ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml"
|
||||
|
||||
.test_template: &test_template
|
||||
stage: integration_test
|
||||
stage: target_test
|
||||
when: on_success
|
||||
only:
|
||||
refs:
|
||||
@ -942,7 +960,7 @@ example_test_002_01:
|
||||
- ESP32
|
||||
- Example_ShieldBox_Basic
|
||||
|
||||
example_test_003_01:
|
||||
.example_test_003_01:
|
||||
<<: *example_test_template
|
||||
tags:
|
||||
- ESP32
|
||||
@ -1522,6 +1540,45 @@ UT_012_03:
|
||||
- UT_T1_1
|
||||
- 8Mpsram
|
||||
|
||||
UT_012_04:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- 8Mpsram
|
||||
|
||||
UT_017_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_1
|
||||
|
||||
UT_017_02:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_1
|
||||
|
||||
UT_017_03:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_1
|
||||
|
||||
UT_017_04:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_1
|
||||
- psram
|
||||
|
||||
UT_017_05:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_1
|
||||
- 8Mpsram
|
||||
|
||||
UT_601_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
@ -1678,6 +1735,18 @@ IT_006_05:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_6
|
||||
|
||||
IT_006_06:
|
||||
<<: *test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_6
|
||||
|
||||
IT_006_07:
|
||||
<<: *test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_6
|
||||
|
||||
IT_007_01:
|
||||
<<: *test_template
|
||||
tags:
|
||||
@ -1690,6 +1759,12 @@ IT_007_02:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_7
|
||||
|
||||
IT_007_03:
|
||||
<<: *test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_7
|
||||
|
||||
IT_008_01:
|
||||
<<: *test_template
|
||||
tags:
|
||||
@ -1720,6 +1795,12 @@ IT_012_01:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_9
|
||||
|
||||
IT_012_02:
|
||||
<<: *test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_9
|
||||
|
||||
IT_013_01:
|
||||
<<: *test_template
|
||||
tags:
|
||||
|
@ -145,8 +145,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
if (it->handle == handle) {
|
||||
// must erase the partition before writing to it
|
||||
assert(it->erased_size > 0 && "must erase the partition before writing to it");
|
||||
|
||||
if(it->wrote_size == 0 && size > 0 && data_bytes[0] != 0xE9) {
|
||||
if (it->wrote_size == 0 && it->partial_bytes == 0 && size > 0 && data_bytes[0] != ESP_IMAGE_HEADER_MAGIC) {
|
||||
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x", data_bytes[0]);
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ externalproject_add(bootloader
|
||||
# TODO: support overriding the bootloader in COMPONENT_PATHS
|
||||
SOURCE_DIR "${IDF_PATH}/components/bootloader/subproject"
|
||||
BINARY_DIR "${bootloader_build_dir}"
|
||||
CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH} -DEXTRA_COMPONENT_DIRS=${COMPONENT_DIRS}
|
||||
-DTESTS_ALL=0 -DTEST_COMPONENTS=""
|
||||
CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH}
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_ALWAYS 1 # no easy way around this...
|
||||
BUILD_BYPRODUCTS ${bootloader_binary_files}
|
||||
|
@ -111,4 +111,21 @@ esp_err_t bootloader_flash_erase_sector(size_t sector);
|
||||
*/
|
||||
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size);
|
||||
|
||||
/* Cache MMU block size */
|
||||
#define MMU_BLOCK_SIZE 0x00010000
|
||||
|
||||
/* Cache MMU address mask (MMU tables ignore bits which are zero) */
|
||||
#define MMU_FLASH_MASK (~(MMU_BLOCK_SIZE - 1))
|
||||
|
||||
/**
|
||||
* @brief Calculate the number of cache pages to map
|
||||
* @param size size of data to map
|
||||
* @param vaddr virtual address where data will be mapped
|
||||
* @return number of cache MMU pages required to do the mapping
|
||||
*/
|
||||
static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vaddr)
|
||||
{
|
||||
return (size + (vaddr - (vaddr & MMU_FLASH_MASK)) + MMU_BLOCK_SIZE - 1) / MMU_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -91,8 +91,6 @@ static const char *TAG = "bootloader_flash";
|
||||
*/
|
||||
#define MMU_BLOCK0_VADDR 0x3f400000
|
||||
#define MMU_BLOCK50_VADDR 0x3f720000
|
||||
#define MMU_FLASH_MASK 0xffff0000
|
||||
#define MMU_BLOCK_SIZE 0x00010000
|
||||
|
||||
static bool mapped;
|
||||
|
||||
@ -112,10 +110,11 @@ const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
|
||||
}
|
||||
|
||||
uint32_t src_addr_aligned = src_addr & MMU_FLASH_MASK;
|
||||
uint32_t count = (size + (src_addr - src_addr_aligned) + 0xffff) / MMU_BLOCK_SIZE;
|
||||
uint32_t count = bootloader_cache_pages_to_map(size, src_addr);
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", src_addr_aligned, count );
|
||||
ESP_LOGD(TAG, "mmu set paddr=%08x count=%d size=%x src_addr=%x src_addr_aligned=%x",
|
||||
src_addr & MMU_FLASH_MASK, count, size, src_addr, src_addr_aligned );
|
||||
int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count);
|
||||
if (e != 0) {
|
||||
ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d\n", e);
|
||||
|
@ -72,6 +72,7 @@ static void wdt_reset_check(void);
|
||||
esp_err_t bootloader_init()
|
||||
{
|
||||
cpu_configure_region_protection();
|
||||
cpu_init_memctl();
|
||||
|
||||
/* Sanity check that static RAM is after the stack */
|
||||
#ifndef NDEBUG
|
||||
|
@ -389,7 +389,7 @@ static void unpack_load_app(const esp_image_metadata_t* data)
|
||||
// Find DROM & IROM addresses, to configure cache mappings
|
||||
for (int i = 0; i < data->image.segment_count; i++) {
|
||||
const esp_image_segment_header_t *header = &data->segments[i];
|
||||
if (header->load_addr >= SOC_IROM_LOW && header->load_addr < SOC_IROM_HIGH) {
|
||||
if (header->load_addr >= SOC_DROM_LOW && header->load_addr < SOC_DROM_HIGH) {
|
||||
if (drom_addr != 0) {
|
||||
ESP_LOGE(TAG, MAP_ERR_MSG, "DROM");
|
||||
} else {
|
||||
@ -399,7 +399,7 @@ static void unpack_load_app(const esp_image_metadata_t* data)
|
||||
drom_load_addr = header->load_addr;
|
||||
drom_size = header->data_len;
|
||||
}
|
||||
if (header->load_addr >= SOC_DROM_LOW && header->load_addr < SOC_DROM_HIGH) {
|
||||
if (header->load_addr >= SOC_IROM_LOW && header->load_addr < SOC_IROM_HIGH) {
|
||||
if (irom_addr != 0) {
|
||||
ESP_LOGE(TAG, MAP_ERR_MSG, "IROM");
|
||||
} else {
|
||||
@ -430,6 +430,7 @@ static void set_cache_and_start_app(
|
||||
uint32_t irom_size,
|
||||
uint32_t entry_addr)
|
||||
{
|
||||
int rc;
|
||||
ESP_LOGD(TAG, "configure drom and irom and start");
|
||||
Cache_Read_Disable( 0 );
|
||||
Cache_Flush( 0 );
|
||||
@ -441,20 +442,34 @@ static void set_cache_and_start_app(
|
||||
DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
|
||||
}
|
||||
|
||||
uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
||||
ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
|
||||
int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||
ESP_LOGV(TAG, "rc=%d", rc );
|
||||
rc = cache_flash_mmu_set( 1, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||
ESP_LOGV(TAG, "rc=%d", rc );
|
||||
uint32_t irom_page_count = (irom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
||||
ESP_LOGV(TAG, "i mmu set paddr=%08x vaddr=%08x size=%d n=%d", irom_addr & 0xffff0000, irom_load_addr & 0xffff0000, irom_size, irom_page_count );
|
||||
rc = cache_flash_mmu_set( 0, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
|
||||
ESP_LOGV(TAG, "rc=%d", rc );
|
||||
rc = cache_flash_mmu_set( 1, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
|
||||
ESP_LOGV(TAG, "rc=%d", rc );
|
||||
DPORT_REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 );
|
||||
DPORT_REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 );
|
||||
uint32_t drom_load_addr_aligned = drom_load_addr & MMU_FLASH_MASK;
|
||||
uint32_t drom_page_count = bootloader_cache_pages_to_map(drom_size, drom_load_addr);
|
||||
ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d",
|
||||
drom_addr & MMU_FLASH_MASK, drom_load_addr_aligned, drom_size, drom_page_count);
|
||||
rc = cache_flash_mmu_set(0, 0, drom_load_addr_aligned, drom_addr & MMU_FLASH_MASK, 64, drom_page_count);
|
||||
ESP_LOGV(TAG, "rc=%d", rc);
|
||||
rc = cache_flash_mmu_set(1, 0, drom_load_addr_aligned, drom_addr & MMU_FLASH_MASK, 64, drom_page_count);
|
||||
ESP_LOGV(TAG, "rc=%d", rc);
|
||||
|
||||
uint32_t irom_load_addr_aligned = irom_load_addr & MMU_FLASH_MASK;
|
||||
uint32_t irom_page_count = bootloader_cache_pages_to_map(irom_size, irom_load_addr);
|
||||
ESP_LOGV(TAG, "i mmu set paddr=%08x vaddr=%08x size=%d n=%d",
|
||||
irom_addr & MMU_FLASH_MASK, irom_load_addr_aligned, irom_size, irom_page_count);
|
||||
rc = cache_flash_mmu_set(0, 0, irom_load_addr_aligned, irom_addr & MMU_FLASH_MASK, 64, irom_page_count);
|
||||
ESP_LOGV(TAG, "rc=%d", rc);
|
||||
rc = cache_flash_mmu_set(1, 0, irom_load_addr_aligned, irom_addr & MMU_FLASH_MASK, 64, irom_page_count);
|
||||
ESP_LOGV(TAG, "rc=%d", rc);
|
||||
|
||||
DPORT_REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG,
|
||||
(DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) |
|
||||
(DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 |
|
||||
DPORT_PRO_CACHE_MASK_DRAM1 );
|
||||
|
||||
DPORT_REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG,
|
||||
(DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) |
|
||||
(DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 |
|
||||
DPORT_APP_CACHE_MASK_DRAM1 );
|
||||
|
||||
Cache_Read_Enable( 0 );
|
||||
|
||||
// Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)
|
||||
|
@ -135,7 +135,6 @@ config BTDM_CONTROLLER_MODEM_SLEEP
|
||||
default y
|
||||
help
|
||||
Enable/disable bluetooth controller low power mode.
|
||||
Note that currently there is problem in the combination use of bluetooth modem sleep and Dynamic Frequency Scaling(DFS). So do not enable DFS if bluetooth modem sleep is in use.
|
||||
|
||||
choice BTDM_MODEM_SLEEP_MODE
|
||||
prompt "Bluetooth Modem sleep mode"
|
||||
@ -146,11 +145,13 @@ choice BTDM_MODEM_SLEEP_MODE
|
||||
config BTDM_MODEM_SLEEP_MODE_ORIG
|
||||
bool "ORIG Mode(sleep with low power clock)"
|
||||
help
|
||||
ORIG mode is a deep sleep mode that can be used for dual mode controller. In this mode, bluetooth controller sleeps between BR/EDR frames and BLE events. A low power clock is used to maintain bluetooth reference clock.
|
||||
ORIG mode is a bluetooth sleep mode that can be used for dual mode controller. In this mode, bluetooth controller
|
||||
sleeps between BR/EDR frames and BLE events. A low power clock is used to maintain bluetooth reference clock.
|
||||
config BTDM_MODEM_SLEEP_MODE_EVED
|
||||
bool "EVED Mode "
|
||||
bool "EVED Mode(For internal test only)"
|
||||
help
|
||||
This mode is for BLE only.
|
||||
EVED mode is for BLE only and is only for internal test. Do not use it for production. this mode is not compatible
|
||||
with DFS nor light sleep
|
||||
endchoice
|
||||
|
||||
choice BTDM_LOW_POWER_CLOCK
|
||||
@ -161,6 +162,10 @@ choice BTDM_LOW_POWER_CLOCK
|
||||
|
||||
config BTDM_LPCLK_SEL_MAIN_XTAL
|
||||
bool "Main crystal"
|
||||
help
|
||||
Main crystal can be used as low power clock for bluetooth modem sleep. If this option is selected, bluetooth
|
||||
modem sleep can work under Dynamic Frequency Scaling(DFS) enabled, but cannot work when light sleep is enabled.
|
||||
Main crystal has a relatively better performance than other bluetooth low power clock sources.
|
||||
config BTDM_LPCLK_SEL_EXT_32K_XTAL
|
||||
bool "External 32kHz crystal"
|
||||
depends on ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||
@ -1180,6 +1185,15 @@ config SMP_ENABLE
|
||||
depends on BLUEDROID_ENABLED
|
||||
default CLASSIC_BT_ENABLED || BLE_SMP_ENABLE
|
||||
|
||||
config BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY
|
||||
bool "Report adv data and scan response individually when BLE active scan"
|
||||
depends on BLUEDROID_ENABLED && (BTDM_CONTROLLER_MODE_BTDM || BTDM_CONTROLLER_MODE_BLE_ONLY)
|
||||
default n
|
||||
help
|
||||
Originally, when doing BLE active scan, Bluedroid will not report adv to application layer
|
||||
until receive scan response. This option is used to disable the behavior. When enable this option,
|
||||
Bluedroid will report adv data or scan response to application layer immediately.
|
||||
|
||||
# Memory reserved at start of DRAM for Bluetooth stack
|
||||
config BT_RESERVE_DRAM
|
||||
hex
|
||||
|
@ -286,7 +286,7 @@ typedef struct {
|
||||
esp_ble_adv_type_t adv_type; /*!< Advertising type */
|
||||
esp_ble_addr_type_t own_addr_type; /*!< Owner bluetooth device address type */
|
||||
esp_bd_addr_t peer_addr; /*!< Peer device bluetooth device address */
|
||||
esp_ble_addr_type_t peer_addr_type; /*!< Peer device bluetooth device address type */
|
||||
esp_ble_addr_type_t peer_addr_type; /*!< Peer device bluetooth device address type, only support public address type and random address type */
|
||||
esp_ble_adv_channel_t channel_map; /*!< Advertising channel map */
|
||||
esp_ble_adv_filter_t adv_filter_policy; /*!< Advertising filter policy */
|
||||
} esp_ble_adv_params_t;
|
||||
@ -303,9 +303,9 @@ typedef struct {
|
||||
Value of 0xFFFF indicates no specific minimum.
|
||||
Values not defined above are reserved for future use.*/
|
||||
|
||||
int max_interval; /*!< Advertising data show slave preferred connection max interval.
|
||||
int max_interval; /*!< Advertising data show slave preferred connection max interval.
|
||||
The connection interval in the following manner:
|
||||
connIntervalmax = Conn_Interval_Max * 1.25 ms
|
||||
connIntervalmax = Conn_Interval_Max * 1.25 ms
|
||||
Conn_Interval_Max range: 0x0006 to 0x0C80
|
||||
Conn_Interval_Max shall be equal to or greater than the Conn_Interval_Min.
|
||||
Value of 0xFFFF indicates no specific maximum.
|
||||
@ -366,8 +366,8 @@ 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
|
||||
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;
|
||||
|
||||
@ -962,8 +962,7 @@ esp_err_t esp_ble_gap_get_local_used_addr(esp_bd_addr_t local_used_addr, uint8_t
|
||||
* @param[in] type - finding ADV data type
|
||||
* @param[out] length - return the length of ADV data not including type
|
||||
*
|
||||
* @return - ESP_OK : success
|
||||
* - other : failed
|
||||
* @return pointer of ADV data
|
||||
*
|
||||
*/
|
||||
uint8_t *esp_ble_resolve_adv_data(uint8_t *adv_data, uint8_t type, uint8_t *length);
|
||||
|
@ -251,9 +251,9 @@ typedef union {
|
||||
} esp_hf_client_cb_param_t;
|
||||
|
||||
/**
|
||||
* @brief HFP client incoming data callback function, the callback is useful in case of
|
||||
* @brief HFP client incoming data callback function, the callback is useful in case of
|
||||
* Voice Over HCI.
|
||||
* @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
|
||||
* @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
|
||||
* buffer is allocated inside bluetooth protocol stack and will be released after
|
||||
* invoke of the callback is finished.
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
@ -261,13 +261,13 @@ typedef union {
|
||||
typedef void (* esp_hf_client_incoming_data_cb_t)(const uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief HFP client outgoing data callback function, the callback is useful in case of
|
||||
* Voice Over HCI. Once audio connection is set up and the application layer has
|
||||
* prepared data to send, the lower layer will call this function to read data
|
||||
* @brief HFP client outgoing data callback function, the callback is useful in case of
|
||||
* Voice Over HCI. Once audio connection is set up and the application layer has
|
||||
* prepared data to send, the lower layer will call this function to read data
|
||||
* and then send. This callback is supposed to be implemented as non-blocking,
|
||||
* and if data is not enough, return value 0 is supposed.
|
||||
*
|
||||
* @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
|
||||
*
|
||||
* @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
|
||||
* buffer is allocated inside bluetooth protocol stack and will be released after
|
||||
* invoke of the callback is finished.
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
@ -326,7 +326,7 @@ esp_err_t esp_hf_client_deinit(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Connect to remote bluetooth HFP audio gateway(AG) device, must after esp_a2d_hf_client_init()
|
||||
* @brief Connect to remote bluetooth HFP audio gateway(AG) device, must after esp_hf_client_init()
|
||||
*
|
||||
* @param[in] remote_bda: remote bluetooth device address
|
||||
*
|
||||
@ -606,7 +606,7 @@ void esp_hf_client_outgoing_data_ready(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the down sampling converter. This is a utility function that can
|
||||
* only be used in the case that Voice Over HCI is enabled.
|
||||
* only be used in the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* @param[in] src_sps: original samples per second(source audio data, i.e. 48000, 32000,
|
||||
* 16000, 44100, 22050, 11025)
|
||||
|
@ -190,8 +190,7 @@ esp_err_t esp_spp_register_callback(esp_spp_cb_t callback);
|
||||
/**
|
||||
* @brief This function is called to init SPP.
|
||||
*
|
||||
* @param[in] mode: Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_CB.
|
||||
* Now only supports ESP_SPP_MODE_CB mode, we will continue to update.
|
||||
* @param[in] mode: Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_VFS.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
|
@ -2666,9 +2666,7 @@ static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NA
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#if (BT_SSP_INCLUDED == TRUE)
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_dm_pinname_cback
|
||||
@ -2725,6 +2723,7 @@ static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NA
|
||||
bta_dm_cb.p_sec_cback(event, &sec_event);
|
||||
}
|
||||
}
|
||||
#endif /// BT_SSP_INCLUDED == TRUE
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@ -2744,18 +2743,6 @@ static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_
|
||||
return BTM_NOT_AUTHORIZED;
|
||||
}
|
||||
|
||||
/* If the device name is not known, save bdaddr and devclass and initiate a name request */
|
||||
if (bd_name[0] == 0) {
|
||||
bta_dm_cb.pin_evt = BTA_DM_PIN_REQ_EVT;
|
||||
bdcpy(bta_dm_cb.pin_bd_addr, bd_addr);
|
||||
BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, dev_class);
|
||||
if ((BTM_ReadRemoteDeviceName(bd_addr, bta_dm_pinname_cback, BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) {
|
||||
return BTM_CMD_STARTED;
|
||||
}
|
||||
|
||||
APPL_TRACE_WARNING(" bta_dm_pin_cback() -> Failed to start Remote Name Request ");
|
||||
}
|
||||
|
||||
bdcpy(sec_event.pin_req.bd_addr, bd_addr);
|
||||
BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, dev_class);
|
||||
BCM_STRNCPY_S((char *)sec_event.pin_req.bd_name, sizeof(BD_NAME), (char *)bd_name, (BD_NAME_LEN - 1));
|
||||
@ -4475,7 +4462,8 @@ void bta_dm_add_ble_device (tBTA_DM_MSG *p_data)
|
||||
{
|
||||
if (!BTM_SecAddBleDevice (p_data->add_ble_device.bd_addr, NULL,
|
||||
p_data->add_ble_device.dev_type ,
|
||||
p_data->add_ble_device.addr_type)) {
|
||||
p_data->add_ble_device.addr_type,
|
||||
p_data->add_ble_device.auth_mode)) {
|
||||
APPL_TRACE_ERROR ("BTA_DM: Error adding BLE Device for device %08x%04x",
|
||||
(p_data->add_ble_device.bd_addr[0] << 24) + (p_data->add_ble_device.bd_addr[1] << 16) + \
|
||||
(p_data->add_ble_device.bd_addr[2] << 8) + p_data->add_ble_device.bd_addr[3],
|
||||
|
@ -797,12 +797,13 @@ void BTA_DmAddBleKey (BD_ADDR bd_addr, tBTA_LE_KEY_VALUE *p_le_key, tBTA_LE_KEY_
|
||||
**
|
||||
** Parameters: bd_addr - BD address of the peer
|
||||
** dev_type - Remote device's device type.
|
||||
** auth_mode - auth mode
|
||||
** addr_type - LE device address type.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBT_DEVICE_TYPE dev_type)
|
||||
void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, int auth_mode, tBT_DEVICE_TYPE dev_type)
|
||||
{
|
||||
tBTA_DM_API_ADD_BLE_DEVICE *p_msg;
|
||||
|
||||
@ -812,6 +813,7 @@ void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBT_DEVICE_TY
|
||||
p_msg->hdr.event = BTA_DM_API_ADD_BLEDEVICE_EVT;
|
||||
bdcpy(p_msg->bd_addr, bd_addr);
|
||||
p_msg->addr_type = addr_type;
|
||||
p_msg->auth_mode = auth_mode;
|
||||
p_msg->dev_type = dev_type;
|
||||
|
||||
bta_sys_sendmsg(p_msg);
|
||||
|
@ -445,6 +445,7 @@ typedef struct {
|
||||
BT_HDR hdr;
|
||||
BD_ADDR bd_addr;
|
||||
tBT_DEVICE_TYPE dev_type ;
|
||||
UINT32 auth_mode;
|
||||
tBLE_ADDR_TYPE addr_type;
|
||||
|
||||
} tBTA_DM_API_ADD_BLE_DEVICE;
|
||||
|
@ -932,6 +932,9 @@ static void bta_gatts_send_request_cback (UINT16 conn_id,
|
||||
cb_data.req_data.trans_id = trans_id;
|
||||
cb_data.req_data.p_data = (tBTA_GATTS_REQ_DATA *)p_data;
|
||||
|
||||
if(req_type == BTA_GATTS_CONF_EVT) {
|
||||
cb_data.req_data.handle = p_data->handle;
|
||||
}
|
||||
(*p_rcb->p_cback)(req_type, &cb_data);
|
||||
} else {
|
||||
APPL_TRACE_ERROR("connection request on gatt_if[%d] is not interested", gatt_if);
|
||||
|
@ -1870,12 +1870,13 @@ extern void BTA_DmBleConfirmReply(BD_ADDR bd_addr, BOOLEAN accept);
|
||||
**
|
||||
** Parameters: bd_addr - BD address of the peer
|
||||
** dev_type - Remote device's device type.
|
||||
** auth_mode - auth mode
|
||||
** addr_type - LE device address type.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type,
|
||||
extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, int auth_mode,
|
||||
tBT_DEVICE_TYPE dev_type);
|
||||
|
||||
|
||||
|
@ -553,6 +553,91 @@ bt_status_t btc_storage_remove_ble_dev_type(bt_bdaddr_t *remote_bd_addr, bool fl
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bt_status_t _btc_storage_set_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, uint8_t auth_mode, bool flush)
|
||||
{
|
||||
int ret;
|
||||
bdstr_t bdstr;
|
||||
|
||||
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr_t));
|
||||
ret = btc_config_set_int(bdstr, BTC_BLE_STORAGE_LE_AUTH_MODE_STR, (int)auth_mode);
|
||||
if (ret == false) {
|
||||
return BT_STATUS_FAIL;
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
_btc_storage_save();
|
||||
}
|
||||
|
||||
return BT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
bt_status_t btc_storage_set_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, uint8_t auth_mode, bool flush)
|
||||
{
|
||||
bt_status_t ret;
|
||||
|
||||
btc_config_lock();
|
||||
ret = _btc_storage_set_ble_dev_auth_mode(remote_bd_addr, auth_mode, flush);
|
||||
btc_config_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bt_status_t _btc_storage_get_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, int* auth_mode)
|
||||
{
|
||||
bdstr_t bdstr;
|
||||
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
|
||||
int ret = btc_config_get_int(bdstr, BTC_BLE_STORAGE_LE_AUTH_MODE_STR, auth_mode);
|
||||
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
|
||||
}
|
||||
|
||||
bt_status_t btc_storage_get_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, int* auth_mode)
|
||||
{
|
||||
bt_status_t ret;
|
||||
|
||||
btc_config_lock();
|
||||
ret = _btc_storage_get_ble_dev_auth_mode(remote_bd_addr, auth_mode);
|
||||
btc_config_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bt_status_t _btc_storage_remove_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, bool flush)
|
||||
{
|
||||
bool ret = true;
|
||||
bdstr_t bdstr;
|
||||
uint32_t auth_mode = 0;
|
||||
|
||||
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
|
||||
|
||||
ret = btc_config_get_int(bdstr, BTC_BLE_STORAGE_LE_AUTH_MODE_STR, (int *)&auth_mode);
|
||||
if (ret == false) {
|
||||
//cannot find the key, just return SUCCESS, indicate already removed
|
||||
return BT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ret = btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_AUTH_MODE_STR);
|
||||
if (ret == false) {
|
||||
return BT_STATUS_FAIL;
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
_btc_storage_save();
|
||||
}
|
||||
|
||||
return BT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
bt_status_t btc_storage_remove_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, bool flush)
|
||||
{
|
||||
bt_status_t ret;
|
||||
|
||||
btc_config_lock();
|
||||
ret = _btc_storage_remove_ble_dev_auth_mode(remote_bd_addr, flush);
|
||||
btc_config_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bt_status_t _btc_storage_set_remote_addr_type(bt_bdaddr_t *remote_bd_addr, uint8_t addr_type, bool flush)
|
||||
{
|
||||
int ret;
|
||||
@ -657,7 +742,11 @@ static void _btc_read_le_key(const uint8_t key_type, const size_t key_len, bt_bd
|
||||
bdcpy(bta_bd_addr, bd_addr.address);
|
||||
|
||||
if (!*device_added) {
|
||||
BTA_DmAddBleDevice(bta_bd_addr, addr_type, BT_DEVICE_TYPE_BLE);
|
||||
int auth_mode = 0;
|
||||
if(_btc_storage_get_ble_dev_auth_mode(&bd_addr, &auth_mode) != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_WARNING("%s Failed to get auth mode from flash, please erase flash and download the firmware again", __func__);
|
||||
}
|
||||
BTA_DmAddBleDevice(bta_bd_addr, addr_type, auth_mode, BT_DEVICE_TYPE_BLE);
|
||||
*device_added = true;
|
||||
}
|
||||
|
||||
|
@ -176,6 +176,7 @@ static void btc_dm_remove_ble_bonding_keys(void)
|
||||
bdcpy(bd_addr.address, pairing_cb.bd_addr);
|
||||
|
||||
btc_storage_remove_remote_addr_type(&bd_addr, false);
|
||||
btc_storage_remove_ble_dev_auth_mode(&bd_addr, false);
|
||||
btc_storage_remove_ble_dev_type(&bd_addr, false);
|
||||
btc_storage_remove_ble_bonding_keys(&bd_addr);
|
||||
}
|
||||
@ -261,9 +262,14 @@ static void btc_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
|
||||
BTC_TRACE_DEBUG ("%s, - pairing_cb.bd_addr: %08x%04x", __func__,
|
||||
(pairing_cb.bd_addr[0] << 24) + (pairing_cb.bd_addr[1] << 16) + (pairing_cb.bd_addr[2] << 8) + pairing_cb.bd_addr[3],
|
||||
(pairing_cb.bd_addr[4] << 8) + pairing_cb.bd_addr[5]);
|
||||
// Check if need to save BLE keys
|
||||
if((p_auth_cmpl->auth_mode & SMP_AUTH_GEN_BOND) == 0) {
|
||||
return;
|
||||
}
|
||||
if (btc_storage_get_remote_addr_type(&bdaddr, &addr_type) != BT_STATUS_SUCCESS) {
|
||||
btc_storage_set_remote_addr_type(&bdaddr, p_auth_cmpl->addr_type, true);
|
||||
}
|
||||
btc_storage_set_ble_dev_auth_mode(&bdaddr, p_auth_cmpl->auth_mode, true);
|
||||
btc_dm_save_ble_bonding_keys();
|
||||
} else {
|
||||
/*Map the HCI fail reason to bt status */
|
||||
@ -638,6 +644,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg)
|
||||
//remove the bonded key in the config and nvs flash.
|
||||
btc_storage_remove_ble_dev_type(&bd_addr, false);
|
||||
btc_storage_remove_remote_addr_type(&bd_addr, false);
|
||||
btc_storage_remove_ble_dev_auth_mode(&bd_addr, false);
|
||||
param.remove_bond_dev_cmpl.status = btc_storage_remove_ble_bonding_keys(&bd_addr);
|
||||
}
|
||||
ble_msg.act = ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT;
|
||||
|
@ -64,7 +64,7 @@ static void btc_init_bluetooth(void)
|
||||
bte_main_boot_entry(btc_init_callback);
|
||||
#if (SMP_INCLUDED)
|
||||
btc_config_init();
|
||||
//load the ble local key whitch has been store in the flash
|
||||
//load the ble local key which has been stored in the flash
|
||||
btc_dm_load_ble_local_keys();
|
||||
#endif /* #if (SMP_INCLUDED) */
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define BTC_BLE_STORAGE_LE_KEY_LENC_STR "LE_KEY_LENC"
|
||||
#define BTC_BLE_STORAGE_LE_KEY_LID_STR "LE_KEY_LID"
|
||||
#define BTC_BLE_STORAGE_LE_KEY_LCSRK_STR "LE_KEY_LCSRK"
|
||||
#define BTC_BLE_STORAGE_LE_AUTH_MODE_STR "AuthMode"
|
||||
|
||||
#define BTC_BLE_STORAGE_LOCAL_ADAPTER_STR "Adapter"
|
||||
#define BTC_BLE_STORAGE_LE_LOCAL_KEY_IR_STR "LE_LOCAL_KEY_IR"
|
||||
@ -66,6 +67,12 @@ bt_status_t btc_storage_remove_ble_local_keys(void);
|
||||
|
||||
bt_status_t btc_storage_get_ble_local_key(uint8_t key_type, char *key_value, int key_len);
|
||||
|
||||
bt_status_t btc_storage_set_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, uint8_t auth_mode, bool flush);
|
||||
|
||||
bt_status_t btc_storage_get_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, int* auth_mode);
|
||||
|
||||
bt_status_t btc_storage_remove_ble_dev_auth_mode(bt_bdaddr_t *remote_bd_addr, bool flush);
|
||||
|
||||
bt_status_t btc_storage_get_remote_addr_type(bt_bdaddr_t *remote_bd_addr, int *addr_type);
|
||||
|
||||
bt_status_t btc_storage_set_remote_addr_type(bt_bdaddr_t *remote_bd_addr, uint8_t addr_type, bool flush);
|
||||
|
@ -143,9 +143,21 @@ static inline void btc_a2d_data_cb_to_app(const uint8_t *data, uint32_t len)
|
||||
}
|
||||
}
|
||||
|
||||
OI_CODEC_SBC_DECODER_CONTEXT context;
|
||||
OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
|
||||
OI_INT16 pcmData[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
|
||||
#define BTC_SBC_DEC_CONTEXT_DATA_LEN (CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS))
|
||||
#define BTC_SBC_DEC_PCM_DATA_LEN (15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS)
|
||||
|
||||
#if BTC_SBC_DEC_DYNAMIC_MEMORY == FALSE
|
||||
static OI_CODEC_SBC_DECODER_CONTEXT btc_sbc_decoder_context;
|
||||
static OI_UINT32 btc_sbc_decoder_context_data[BTC_SBC_DEC_CONTEXT_DATA_LEN];
|
||||
static OI_INT16 btc_sbc_pcm_data[BTC_SBC_DEC_PCM_DATA_LEN];
|
||||
#else
|
||||
static OI_CODEC_SBC_DECODER_CONTEXT *btc_sbc_decoder_context_ptr;
|
||||
static OI_UINT32 *btc_sbc_decoder_context_data;
|
||||
static OI_INT16 *btc_sbc_pcm_data;
|
||||
#define btc_sbc_decoder_context (*btc_sbc_decoder_context_ptr)
|
||||
#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == FALSE */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Misc helper functions
|
||||
@ -235,6 +247,16 @@ bool btc_a2dp_sink_startup(void)
|
||||
|
||||
APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##");
|
||||
|
||||
#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE)
|
||||
btc_sbc_decoder_context_ptr = osi_calloc(sizeof(OI_CODEC_SBC_DECODER_CONTEXT));
|
||||
btc_sbc_decoder_context_data = osi_calloc(BTC_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32));
|
||||
btc_sbc_pcm_data = osi_calloc(BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16));
|
||||
if (!btc_sbc_decoder_context_ptr || !btc_sbc_decoder_context_data || !btc_sbc_pcm_data) {
|
||||
APPL_TRACE_ERROR("failed to allocate SBC decoder");
|
||||
goto error_exit;
|
||||
}
|
||||
#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */
|
||||
|
||||
btc_aa_snk_queue_set = xQueueCreateSet(BTC_A2DP_SINK_TASK_QUEUE_SET_LEN);
|
||||
configASSERT(btc_aa_snk_queue_set);
|
||||
btc_aa_snk_data_queue = xQueueCreate(BTC_A2DP_SINK_DATA_QUEUE_LEN, sizeof(int32_t));
|
||||
@ -280,6 +302,21 @@ error_exit:;
|
||||
vQueueDelete(btc_aa_snk_queue_set);
|
||||
btc_aa_snk_queue_set = NULL;
|
||||
}
|
||||
#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE)
|
||||
if (btc_sbc_decoder_context_ptr) {
|
||||
osi_free(btc_sbc_decoder_context_ptr);
|
||||
btc_sbc_decoder_context_ptr = NULL;
|
||||
}
|
||||
if (btc_sbc_decoder_context_data) {
|
||||
osi_free(btc_sbc_decoder_context_data);
|
||||
btc_sbc_decoder_context_data = NULL;
|
||||
}
|
||||
if (btc_sbc_pcm_data) {
|
||||
osi_free(btc_sbc_pcm_data);
|
||||
btc_sbc_pcm_data = NULL;
|
||||
}
|
||||
#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -306,6 +343,17 @@ void btc_a2dp_sink_shutdown(void)
|
||||
|
||||
vQueueDelete(btc_aa_snk_queue_set);
|
||||
btc_aa_snk_queue_set = NULL;
|
||||
|
||||
#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE)
|
||||
osi_free(btc_sbc_decoder_context_ptr);
|
||||
btc_sbc_decoder_context_ptr = NULL;
|
||||
|
||||
osi_free(btc_sbc_decoder_context_data);
|
||||
btc_sbc_decoder_context_data = NULL;
|
||||
|
||||
osi_free(btc_sbc_pcm_data);
|
||||
btc_sbc_pcm_data = NULL;
|
||||
#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -467,7 +515,8 @@ static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg
|
||||
|
||||
btc_aa_snk_cb.rx_flush = FALSE;
|
||||
APPL_TRACE_EVENT("Reset to sink role");
|
||||
status = OI_CODEC_SBC_DecoderReset(&context, contextData, sizeof(contextData), 2, 2, FALSE);
|
||||
status = OI_CODEC_SBC_DecoderReset(&btc_sbc_decoder_context, btc_sbc_decoder_context_data,
|
||||
BTC_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 2, 2, FALSE);
|
||||
if (!OI_SUCCESS(status)) {
|
||||
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
|
||||
}
|
||||
@ -582,11 +631,11 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
|
||||
int count;
|
||||
UINT32 pcmBytes, availPcmBytes;
|
||||
OI_INT16 *pcmDataPointer = pcmData; /*Will be overwritten on next packet receipt*/
|
||||
OI_INT16 *pcmDataPointer = btc_sbc_pcm_data; /*Will be overwritten on next packet receipt*/
|
||||
OI_STATUS status;
|
||||
int num_sbc_frames = p_msg->num_frames_to_be_processed;
|
||||
UINT32 sbc_frame_len = p_msg->len - 1;
|
||||
availPcmBytes = sizeof(pcmData);
|
||||
availPcmBytes = BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16);
|
||||
|
||||
/* XXX: Check if the below check is correct, we are checking for peer to be sink when we are sink */
|
||||
if (btc_av_get_peer_sep() == AVDT_TSEP_SNK || (btc_aa_snk_cb.rx_flush)) {
|
||||
@ -603,7 +652,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
|
||||
for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) {
|
||||
pcmBytes = availPcmBytes;
|
||||
status = OI_CODEC_SBC_DecodeFrame(&context, (const OI_BYTE **)&sbc_start_frame,
|
||||
status = OI_CODEC_SBC_DecodeFrame(&btc_sbc_decoder_context, (const OI_BYTE **)&sbc_start_frame,
|
||||
(OI_UINT32 *)&sbc_frame_len,
|
||||
(OI_INT16 *)pcmDataPointer,
|
||||
(OI_UINT32 *)&pcmBytes);
|
||||
@ -617,7 +666,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
p_msg->len = sbc_frame_len + 1;
|
||||
}
|
||||
|
||||
btc_a2d_data_cb_to_app((uint8_t *)pcmData, (sizeof(pcmData) - availPcmBytes));
|
||||
btc_a2d_data_cb_to_app((uint8_t *)btc_sbc_pcm_data, (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -156,7 +156,6 @@ typedef struct {
|
||||
tBTC_AV_FEEDING_MODE feeding_mode;
|
||||
tBTC_AV_MEDIA_FEEDINGS_STATE media_feeding_state;
|
||||
tBTC_AV_MEDIA_FEEDINGS media_feeding;
|
||||
SBC_ENC_PARAMS encoder;
|
||||
osi_alarm_t *media_alarm;
|
||||
} tBTC_A2DP_SOURCE_CB;
|
||||
|
||||
@ -187,6 +186,13 @@ static QueueSetHandle_t btc_aa_src_queue_set;
|
||||
static esp_a2d_source_data_cb_t btc_aa_src_data_cb = NULL;
|
||||
static UINT64 last_frame_us = 0;
|
||||
|
||||
#if BTC_SBC_ENC_DYNAMIC_MEMORY == FALSE
|
||||
static SBC_ENC_PARAMS btc_sbc_encoder;
|
||||
#else
|
||||
static SBC_ENC_PARAMS *btc_sbc_encoder_ptr;
|
||||
#define btc_sbc_encoder (*btc_sbc_encoder_ptr)
|
||||
#endif /* BTC_SBC_ENC_DYNAMIC_MEMORY == FALSE */
|
||||
|
||||
void btc_a2dp_src_reg_data_cb(esp_a2d_source_data_cb_t callback)
|
||||
{
|
||||
// todo: critical section protection
|
||||
@ -310,6 +316,14 @@ bool btc_a2dp_source_startup(void)
|
||||
|
||||
APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##");
|
||||
|
||||
#if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE
|
||||
btc_sbc_encoder_ptr = osi_calloc(sizeof(SBC_ENC_PARAMS));
|
||||
if (!btc_sbc_encoder_ptr) {
|
||||
APPL_TRACE_ERROR("failed to allocate SBC encoder");
|
||||
goto error_exit;
|
||||
}
|
||||
#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */
|
||||
|
||||
btc_aa_src_queue_set = xQueueCreateSet(BTC_A2DP_SOURCE_TASK_QUEUE_SET_LEN);
|
||||
configASSERT(btc_aa_src_queue_set);
|
||||
btc_aa_src_data_queue = xQueueCreate(BTC_A2DP_SOURCE_DATA_QUEUE_LEN, sizeof(void *));
|
||||
@ -355,6 +369,12 @@ error_exit:;
|
||||
vQueueDelete(btc_aa_src_queue_set);
|
||||
btc_aa_src_queue_set = NULL;
|
||||
}
|
||||
#if (BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE)
|
||||
if (btc_sbc_encoder_ptr) {
|
||||
osi_free(btc_sbc_encoder_ptr);
|
||||
btc_sbc_encoder_ptr = NULL;
|
||||
}
|
||||
#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -381,6 +401,11 @@ void btc_a2dp_source_shutdown(void)
|
||||
|
||||
vQueueDelete(btc_aa_src_queue_set);
|
||||
btc_aa_src_queue_set = NULL;
|
||||
|
||||
#if (BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE)
|
||||
osi_free(btc_sbc_encoder_ptr);
|
||||
btc_sbc_encoder_ptr = NULL;
|
||||
#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -794,13 +819,14 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg)
|
||||
btc_aa_src_cb.timestamp = 0;
|
||||
|
||||
/* SBC encoder config (enforced even if not used) */
|
||||
btc_aa_src_cb.encoder.s16ChannelMode = pInitAudio->ChannelMode;
|
||||
btc_aa_src_cb.encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks;
|
||||
btc_aa_src_cb.encoder.s16AllocationMethod = pInitAudio->AllocationMethod;
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq = pInitAudio->SamplingFreq;
|
||||
|
||||
btc_aa_src_cb.encoder.u16BitRate = btc_a2dp_source_get_sbc_rate();
|
||||
btc_sbc_encoder.s16ChannelMode = pInitAudio->ChannelMode;
|
||||
btc_sbc_encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
|
||||
btc_sbc_encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks;
|
||||
btc_sbc_encoder.s16AllocationMethod = pInitAudio->AllocationMethod;
|
||||
btc_sbc_encoder.s16SamplingFreq = pInitAudio->SamplingFreq;
|
||||
|
||||
btc_sbc_encoder.u16BitRate = btc_a2dp_source_get_sbc_rate();
|
||||
|
||||
/* Default transcoding is PCM to SBC, modified by feeding configuration */
|
||||
btc_aa_src_cb.TxTranscoding = BTC_MEDIA_TRSCD_PCM_2_SBC;
|
||||
@ -811,14 +837,14 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg)
|
||||
APPL_TRACE_EVENT("btc_a2dp_source_enc_init mtu %d, peer mtu %d",
|
||||
btc_aa_src_cb.TxAaMtuSize, pInitAudio->MtuSize);
|
||||
APPL_TRACE_EVENT(" ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d",
|
||||
btc_aa_src_cb.encoder.s16ChannelMode, btc_aa_src_cb.encoder.s16NumOfSubBands,
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks,
|
||||
btc_aa_src_cb.encoder.s16AllocationMethod, btc_aa_src_cb.encoder.u16BitRate,
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq);
|
||||
btc_sbc_encoder.s16ChannelMode, btc_sbc_encoder.s16NumOfSubBands,
|
||||
btc_sbc_encoder.s16NumOfBlocks,
|
||||
btc_sbc_encoder.s16AllocationMethod, btc_sbc_encoder.u16BitRate,
|
||||
btc_sbc_encoder.s16SamplingFreq);
|
||||
|
||||
/* Reset entirely the SBC encoder */
|
||||
SBC_Encoder_Init(&(btc_aa_src_cb.encoder));
|
||||
APPL_TRACE_DEBUG("btc_a2dp_source_enc_init bit pool %d", btc_aa_src_cb.encoder.s16BitPool);
|
||||
SBC_Encoder_Init(&(btc_sbc_encoder));
|
||||
APPL_TRACE_DEBUG("btc_a2dp_source_enc_init bit pool %d", btc_sbc_encoder.s16BitPool);
|
||||
}
|
||||
|
||||
|
||||
@ -835,7 +861,7 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg)
|
||||
static void btc_a2dp_source_enc_update(BT_HDR *p_msg)
|
||||
{
|
||||
tBTC_MEDIA_UPDATE_AUDIO *pUpdateAudio = (tBTC_MEDIA_UPDATE_AUDIO *) p_msg;
|
||||
SBC_ENC_PARAMS *pstrEncParams = &btc_aa_src_cb.encoder;
|
||||
SBC_ENC_PARAMS *pstrEncParams = &btc_sbc_encoder;
|
||||
UINT16 s16SamplingFreq;
|
||||
SINT16 s16BitPool = 0;
|
||||
SINT16 s16BitRate;
|
||||
@ -928,19 +954,19 @@ static void btc_a2dp_source_enc_update(BT_HDR *p_msg)
|
||||
if (s16BitPool > pUpdateAudio->MaxBitPool) {
|
||||
APPL_TRACE_DEBUG("%s computed bitpool too large (%d)", __FUNCTION__, s16BitPool);
|
||||
/* Decrease bitrate */
|
||||
btc_aa_src_cb.encoder.u16BitRate -= BTC_MEDIA_BITRATE_STEP;
|
||||
btc_sbc_encoder.u16BitRate -= BTC_MEDIA_BITRATE_STEP;
|
||||
/* Record that we have decreased the bitrate */
|
||||
protect |= 1;
|
||||
} else if (s16BitPool < pUpdateAudio->MinBitPool) {
|
||||
APPL_TRACE_WARNING("%s computed bitpool too small (%d)", __FUNCTION__, s16BitPool);
|
||||
|
||||
/* Increase bitrate */
|
||||
UINT16 previous_u16BitRate = btc_aa_src_cb.encoder.u16BitRate;
|
||||
btc_aa_src_cb.encoder.u16BitRate += BTC_MEDIA_BITRATE_STEP;
|
||||
UINT16 previous_u16BitRate = btc_sbc_encoder.u16BitRate;
|
||||
btc_sbc_encoder.u16BitRate += BTC_MEDIA_BITRATE_STEP;
|
||||
/* Record that we have increased the bitrate */
|
||||
protect |= 2;
|
||||
/* Check over-flow */
|
||||
if (btc_aa_src_cb.encoder.u16BitRate < previous_u16BitRate) {
|
||||
if (btc_sbc_encoder.u16BitRate < previous_u16BitRate) {
|
||||
protect |= 3;
|
||||
}
|
||||
} else {
|
||||
@ -957,10 +983,10 @@ static void btc_a2dp_source_enc_update(BT_HDR *p_msg)
|
||||
pstrEncParams->s16BitPool = s16BitPool;
|
||||
|
||||
APPL_TRACE_DEBUG("%s final bit rate %d, final bit pool %d", __FUNCTION__,
|
||||
btc_aa_src_cb.encoder.u16BitRate, btc_aa_src_cb.encoder.s16BitPool);
|
||||
btc_sbc_encoder.u16BitRate, btc_sbc_encoder.s16BitPool);
|
||||
|
||||
/* make sure we reinitialize encoder with new settings */
|
||||
SBC_Encoder_Init(&(btc_aa_src_cb.encoder));
|
||||
SBC_Encoder_Init(&(btc_sbc_encoder));
|
||||
}
|
||||
}
|
||||
|
||||
@ -991,10 +1017,10 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin
|
||||
case 32000:
|
||||
case 48000:
|
||||
/* For these sampling_freq the AV connection must be 48000 */
|
||||
if (btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf48000) {
|
||||
if (btc_sbc_encoder.s16SamplingFreq != SBC_sf48000) {
|
||||
/* Reconfiguration needed at 48000 */
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed at 48000");
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf48000;
|
||||
btc_sbc_encoder.s16SamplingFreq = SBC_sf48000;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
break;
|
||||
@ -1003,10 +1029,10 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin
|
||||
case 22050:
|
||||
case 44100:
|
||||
/* For these sampling_freq the AV connection must be 44100 */
|
||||
if (btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf44100) {
|
||||
if (btc_sbc_encoder.s16SamplingFreq != SBC_sf44100) {
|
||||
/* Reconfiguration needed at 44100 */
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed at 44100");
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf44100;
|
||||
btc_sbc_encoder.s16SamplingFreq = SBC_sf44100;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
break;
|
||||
@ -1016,21 +1042,21 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin
|
||||
}
|
||||
|
||||
/* Some AV Headsets do not support Mono => always ask for Stereo */
|
||||
if (btc_aa_src_cb.encoder.s16ChannelMode == SBC_MONO) {
|
||||
if (btc_sbc_encoder.s16ChannelMode == SBC_MONO) {
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed in Stereo");
|
||||
btc_aa_src_cb.encoder.s16ChannelMode = SBC_JOINT_STEREO;
|
||||
btc_sbc_encoder.s16ChannelMode = SBC_JOINT_STEREO;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
|
||||
if (reconfig_needed != FALSE) {
|
||||
APPL_TRACE_DEBUG("%s :: mtu %d", __FUNCTION__, btc_aa_src_cb.TxAaMtuSize);
|
||||
APPL_TRACE_DEBUG("ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d",
|
||||
btc_aa_src_cb.encoder.s16ChannelMode,
|
||||
btc_aa_src_cb.encoder.s16NumOfSubBands, btc_aa_src_cb.encoder.s16NumOfBlocks,
|
||||
btc_aa_src_cb.encoder.s16AllocationMethod, btc_aa_src_cb.encoder.u16BitRate,
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq);
|
||||
btc_sbc_encoder.s16ChannelMode,
|
||||
btc_sbc_encoder.s16NumOfSubBands, btc_sbc_encoder.s16NumOfBlocks,
|
||||
btc_sbc_encoder.s16AllocationMethod, btc_sbc_encoder.u16BitRate,
|
||||
btc_sbc_encoder.s16SamplingFreq);
|
||||
|
||||
SBC_Encoder_Init(&(btc_aa_src_cb.encoder));
|
||||
SBC_Encoder_Init(&(btc_sbc_encoder));
|
||||
} else {
|
||||
APPL_TRACE_DEBUG("%s no SBC reconfig needed", __FUNCTION__);
|
||||
}
|
||||
@ -1105,8 +1131,8 @@ static UINT8 btc_get_num_aa_frame(void)
|
||||
|
||||
switch (btc_aa_src_cb.TxTranscoding) {
|
||||
case BTC_MEDIA_TRSCD_PCM_2_SBC: {
|
||||
UINT32 pcm_bytes_per_frame = btc_aa_src_cb.encoder.s16NumOfSubBands *
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks *
|
||||
UINT32 pcm_bytes_per_frame = btc_sbc_encoder.s16NumOfSubBands *
|
||||
btc_sbc_encoder.s16NumOfBlocks *
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.num_channel *
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
|
||||
|
||||
@ -1162,12 +1188,12 @@ static UINT8 btc_get_num_aa_frame(void)
|
||||
|
||||
BOOLEAN btc_media_aa_read_feeding(void)
|
||||
{
|
||||
UINT16 blocm_x_subband = btc_aa_src_cb.encoder.s16NumOfSubBands * \
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks;
|
||||
UINT16 blocm_x_subband = btc_sbc_encoder.s16NumOfSubBands * \
|
||||
btc_sbc_encoder.s16NumOfBlocks;
|
||||
UINT32 read_size;
|
||||
UINT16 sbc_sampling = 48000;
|
||||
UINT32 src_samples;
|
||||
UINT16 bytes_needed = blocm_x_subband * btc_aa_src_cb.encoder.s16NumOfChannels * \
|
||||
UINT16 bytes_needed = blocm_x_subband * btc_sbc_encoder.s16NumOfChannels * \
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
|
||||
static UINT16 up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
|
||||
* SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2];
|
||||
@ -1181,7 +1207,7 @@ BOOLEAN btc_media_aa_read_feeding(void)
|
||||
UINT32 nb_byte_read = 0;
|
||||
|
||||
/* Get the SBC sampling rate */
|
||||
switch (btc_aa_src_cb.encoder.s16SamplingFreq) {
|
||||
switch (btc_sbc_encoder.s16SamplingFreq) {
|
||||
case SBC_sf48000:
|
||||
sbc_sampling = 48000;
|
||||
break;
|
||||
@ -1199,7 +1225,7 @@ BOOLEAN btc_media_aa_read_feeding(void)
|
||||
if (sbc_sampling == btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq) {
|
||||
read_size = bytes_needed - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue;
|
||||
nb_byte_read = btc_aa_src_data_read(
|
||||
((uint8_t *)btc_aa_src_cb.encoder.as16PcmBuffer) +
|
||||
((uint8_t *)btc_sbc_encoder.as16PcmBuffer) +
|
||||
btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue,
|
||||
read_size);
|
||||
if (nb_byte_read == read_size) {
|
||||
@ -1293,7 +1319,7 @@ BOOLEAN btc_media_aa_read_feeding(void)
|
||||
/* only copy the pcm sample when we have up-sampled enough PCM */
|
||||
if (btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue >= bytes_needed) {
|
||||
/* Copy the output pcm samples in SBC encoding buffer */
|
||||
memcpy((UINT8 *)btc_aa_src_cb.encoder.as16PcmBuffer,
|
||||
memcpy((UINT8 *)btc_sbc_encoder.as16PcmBuffer,
|
||||
(UINT8 *)up_sampled_buffer,
|
||||
bytes_needed);
|
||||
/* update the residue */
|
||||
@ -1322,8 +1348,8 @@ BOOLEAN btc_media_aa_read_feeding(void)
|
||||
static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT16 blocm_x_subband = btc_aa_src_cb.encoder.s16NumOfSubBands *
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks;
|
||||
UINT16 blocm_x_subband = btc_sbc_encoder.s16NumOfSubBands *
|
||||
btc_sbc_encoder.s16NumOfBlocks;
|
||||
|
||||
while (nb_frame) {
|
||||
if (NULL == (p_buf = osi_malloc(BTC_MEDIA_AA_BUF_SIZE))) {
|
||||
@ -1339,27 +1365,27 @@ static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)
|
||||
|
||||
do {
|
||||
/* Write @ of allocated buffer in encoder.pu8Packet */
|
||||
btc_aa_src_cb.encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len;
|
||||
btc_sbc_encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len;
|
||||
/* Fill allocated buffer with 0 */
|
||||
memset(btc_aa_src_cb.encoder.as16PcmBuffer, 0, blocm_x_subband
|
||||
* btc_aa_src_cb.encoder.s16NumOfChannels);
|
||||
memset(btc_sbc_encoder.as16PcmBuffer, 0, blocm_x_subband
|
||||
* btc_sbc_encoder.s16NumOfChannels);
|
||||
|
||||
/* Read PCM data and upsample them if needed */
|
||||
if (btc_media_aa_read_feeding()) {
|
||||
/* SBC encode and descramble frame */
|
||||
SBC_Encoder(&(btc_aa_src_cb.encoder));
|
||||
A2D_SbcChkFrInit(btc_aa_src_cb.encoder.pu8Packet);
|
||||
A2D_SbcDescramble(btc_aa_src_cb.encoder.pu8Packet, btc_aa_src_cb.encoder.u16PacketLength);
|
||||
SBC_Encoder(&(btc_sbc_encoder));
|
||||
A2D_SbcChkFrInit(btc_sbc_encoder.pu8Packet);
|
||||
A2D_SbcDescramble(btc_sbc_encoder.pu8Packet, btc_sbc_encoder.u16PacketLength);
|
||||
/* Update SBC frame length */
|
||||
p_buf->len += btc_aa_src_cb.encoder.u16PacketLength;
|
||||
p_buf->len += btc_sbc_encoder.u16PacketLength;
|
||||
nb_frame--;
|
||||
p_buf->layer_specific++;
|
||||
} else {
|
||||
APPL_TRACE_WARNING("btc_media_aa_prep_sbc_2_send underflow %d, %d",
|
||||
nb_frame, btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue);
|
||||
btc_aa_src_cb.media_feeding_state.pcm.counter += nb_frame *
|
||||
btc_aa_src_cb.encoder.s16NumOfSubBands *
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks *
|
||||
btc_sbc_encoder.s16NumOfSubBands *
|
||||
btc_sbc_encoder.s16NumOfBlocks *
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.num_channel *
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
|
||||
/* no more pcm to read */
|
||||
@ -1372,7 +1398,7 @@ static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)
|
||||
}
|
||||
}
|
||||
|
||||
} while (((p_buf->len + btc_aa_src_cb.encoder.u16PacketLength) < btc_aa_src_cb.TxAaMtuSize)
|
||||
} while (((p_buf->len + btc_sbc_encoder.u16PacketLength) < btc_aa_src_cb.TxAaMtuSize)
|
||||
&& (p_buf->layer_specific < 0x0F) && nb_frame);
|
||||
|
||||
if (p_buf->len) {
|
||||
|
@ -452,6 +452,10 @@ static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params, tBT
|
||||
status = ESP_BT_STATUS_PARM_INVALID;
|
||||
BTC_TRACE_ERROR("Invalid advertisting channel map parameters.\n");
|
||||
}
|
||||
if (!BLE_ISVALID_PARAM(ble_adv_params->peer_addr_type, BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_RANDOM)) {
|
||||
status = ESP_BT_STATUS_PARM_INVALID;
|
||||
BTC_TRACE_ERROR("Invalid advertisting peer address type parameters.\n");
|
||||
}
|
||||
if(status != ESP_BT_STATUS_SUCCESS) {
|
||||
if(start_adv_cback) {
|
||||
start_adv_cback(status);
|
||||
@ -831,7 +835,7 @@ static void btc_ble_set_rand_addr (BD_ADDR rand_addr, tBTA_SET_RAND_ADDR_CBACK *
|
||||
BTA_DmSetRandAddress(rand_addr, btc_set_rand_addr_callback);
|
||||
} else {
|
||||
btc_set_rand_addr_callback(BTM_INVALID_STATIC_RAND_ADDR);
|
||||
BTC_TRACE_ERROR("Invalid random address, the high bit should be 0b11, all bits of the random part shall not be to 1 or 0");
|
||||
BTC_TRACE_ERROR("Invalid random address, the high bit should be 0b11, bits of the random part shall not be all 1 or 0");
|
||||
}
|
||||
} else {
|
||||
btc_set_rand_addr_callback(BTM_INVALID_STATIC_RAND_ADDR);
|
||||
|
@ -750,7 +750,7 @@ void btc_gap_bt_arg_deep_free(btc_msg_t *msg)
|
||||
break;
|
||||
#endif ///BT_SSP_INCLUDED == TRUE
|
||||
default:
|
||||
BTC_TRACE_ERROR("Unhandled deep copy %d\n", msg->act);
|
||||
BTC_TRACE_ERROR("Unhandled deep copy %d, arg: %p\n", msg->act, arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -324,6 +324,12 @@
|
||||
#define GATTS_SEND_SERVICE_CHANGE_MODE CONFIG_GATTS_SEND_SERVICE_CHANGE_MODE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY
|
||||
#define BTM_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY FALSE
|
||||
#else
|
||||
#define BTM_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY CONFIG_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY
|
||||
#endif
|
||||
|
||||
/* This feature is used to eanble interleaved scan*/
|
||||
#ifndef BTA_HOST_INTERLEAVE_SEARCH
|
||||
#define BTA_HOST_INTERLEAVE_SEARCH FALSE//FALSE
|
||||
|
@ -250,10 +250,10 @@ static void start_up(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (simple_pairing_supported) {
|
||||
response = AWAIT_COMMAND(packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK));
|
||||
packet_parser->parse_generic_command_complete(response);
|
||||
}
|
||||
|
||||
response = AWAIT_COMMAND(packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK));
|
||||
packet_parser->parse_generic_command_complete(response);
|
||||
|
||||
|
||||
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
||||
response = AWAIT_COMMAND(packet_factory->make_write_sync_flow_control_enable(1));
|
||||
|
@ -43,7 +43,7 @@
|
||||
//#include "osi/include/log.h"
|
||||
|
||||
#if SMP_INCLUDED == TRUE
|
||||
// The temp variable to pass parameter between functions when in the connected event comeback.
|
||||
// The temp variable to pass parameter between functions when in the connected event callback.
|
||||
static BOOLEAN temp_enhanced = FALSE;
|
||||
extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length,
|
||||
UINT16 tlen, UINT8 *p_signature);
|
||||
@ -66,13 +66,14 @@ extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr);
|
||||
** bd_name - Name of the peer device. NULL if unknown.
|
||||
** dev_type - Remote device's device type.
|
||||
** addr_type - LE device address type.
|
||||
** auth_mode - auth mode
|
||||
**
|
||||
** Returns TRUE if added OK, else FALSE
|
||||
**
|
||||
*******************************************************************************/
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type,
|
||||
tBLE_ADDR_TYPE addr_type)
|
||||
tBLE_ADDR_TYPE addr_type, UINT32 auth_mode)
|
||||
{
|
||||
tBTM_SEC_DEV_REC *p_dev_rec;
|
||||
UINT8 i = 0;
|
||||
@ -125,6 +126,7 @@ BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE d
|
||||
}
|
||||
p_dev_rec->device_type |= dev_type;
|
||||
p_dev_rec->ble.ble_addr_type = addr_type;
|
||||
p_dev_rec->ble.auth_mode = auth_mode;
|
||||
|
||||
memcpy (p_dev_rec->ble.pseudo_addr, bd_addr, BD_ADDR_LEN);
|
||||
/* sync up with the Inq Data base*/
|
||||
@ -629,7 +631,7 @@ void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR
|
||||
|
||||
*p_addr_type = BLE_ADDR_PUBLIC;
|
||||
|
||||
if (!p_dev_rec) {
|
||||
if (!p_dev_rec) {
|
||||
*p_dev_type = BT_DEVICE_TYPE_BREDR;
|
||||
/* Check with the BT manager if details about remote device are known */
|
||||
if (p_inq_info != NULL) {
|
||||
@ -1471,7 +1473,7 @@ tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 lin
|
||||
if(link_role == BTM_ROLE_SLAVE && (p_rec->ble.key_type & BTM_LE_KEY_PENC)) {
|
||||
p_rec->ble.skip_update_conn_param = true;
|
||||
} else {
|
||||
p_rec->ble.skip_update_conn_param = false;
|
||||
p_rec->ble.skip_update_conn_param = false;
|
||||
}
|
||||
if (SMP_Pair(bd_addr) == SMP_STARTED) {
|
||||
cmd = BTM_CMD_STARTED;
|
||||
@ -1620,7 +1622,7 @@ void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable)
|
||||
/* to notify GATT to send data if any request is pending */
|
||||
gatt_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr);
|
||||
}
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -1946,10 +1948,10 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
|
||||
|
||||
/* It will cause that scanner doesn't send scan request to advertiser
|
||||
* which has sent IRK to us and we have stored the IRK in controller.
|
||||
* It is a design problem of hardware. The temporal solution is not to
|
||||
* send the key to the controller and then resolve the random address in host.
|
||||
* so we need send the real address information to controller to connect.
|
||||
* Once the connection is successful, resolve device address whether it is
|
||||
* It is a hardware limitation. The preliminary solution is not to
|
||||
* send key to the controller, but to resolve the random address in host.
|
||||
* so we need send the real address information to controller to connect.
|
||||
* Once the connection is successful, resolve device address whether it is
|
||||
* slave or master*/
|
||||
|
||||
/* if (!match && role == HCI_ROLE_SLAVE && BTM_BLE_IS_RESOLVE_BDA(bda)) { */
|
||||
|
@ -3019,7 +3019,9 @@ BOOLEAN btm_ble_update_inq_result(BD_ADDR bda, tINQ_DB_ENT *p_i, UINT8 addr_type
|
||||
BTM_TRACE_DEBUG("btm_ble_update_inq_result scan_rsp=false, to_report=false,\
|
||||
scan_type_active=%d", btm_cb.ble_ctr_cb.inq_var.scan_type);
|
||||
p_i->scan_rsp = FALSE;
|
||||
#if BTM_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY == FALSE
|
||||
to_report = FALSE;
|
||||
#endif
|
||||
} else {
|
||||
p_i->scan_rsp = TRUE;
|
||||
}
|
||||
@ -3316,9 +3318,26 @@ 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 higgher layer
|
||||
/* Event_Type:
|
||||
0x00 Connectable undirected advertising (ADV_IND).
|
||||
0x01 Connectable directed advertising (ADV_DIRECT_IND)
|
||||
0x02 Scannable undirected advertising (ADV_SCAN_IND)
|
||||
0x03 Non connectable undirected advertising (ADV_NONCONN_IND)
|
||||
0x04 Scan Response (SCAN_RSP)
|
||||
0x05-0xFF Reserved for future use
|
||||
*/
|
||||
//if scan duplicate is enabled, the adv packet without scan response is allowed to report to higher 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) {
|
||||
/*
|
||||
Bluedroid will put the advertising packet and scan response into a packet and send it to the higher layer.
|
||||
If two advertising packets are not with the same address, or can't be combined into a packet, then the first advertising
|
||||
packet will be discarded. So we added the following judgment:
|
||||
1. For different addresses, send the last advertising packet to higher layer
|
||||
2. For same address and same advertising type (not scan response), send the last advertising packet to higher layer
|
||||
3. For same address and scan response, do nothing
|
||||
*/
|
||||
int same_addr = memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN);
|
||||
if (same_addr != 0 || (same_addr == 0 && evt_type != BTM_BLE_SCAN_RSP_EVT)) {
|
||||
btm_ble_process_last_adv_pkt();
|
||||
}
|
||||
}
|
||||
|
@ -771,8 +771,8 @@ BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec)
|
||||
}
|
||||
/* It will cause that scanner doesn't send scan request to advertiser
|
||||
* which has sent IRK to us and we have stored the IRK in controller.
|
||||
* It is a design problem of hardware. The temporal solution is not to
|
||||
* send the key to the controller and then resolve the random address in host. */
|
||||
* It is a hardware limitation. The preliminary solution is not to
|
||||
* send key to the controller, but to resolve the random address in host. */
|
||||
/*
|
||||
BTM_TRACE_DEBUG("%s:adding device to controller resolving list\n", __func__);
|
||||
UINT8 *peer_irk = p_dev_rec->ble.keys.irk;
|
||||
|
@ -5030,42 +5030,13 @@ void btm_sec_pin_code_request (UINT8 *p_bda)
|
||||
memcpy (p_cb->connecting_bda, p_bda, BD_ADDR_LEN);
|
||||
memcpy (p_cb->connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
|
||||
|
||||
/* Check if the name is known */
|
||||
/* Even if name is not known we might not be able to get one */
|
||||
/* this is the case when we are already getting something from the */
|
||||
/* device, so HCI level is flow controlled */
|
||||
/* Also cannot send remote name request while paging, i.e. connection is not completed */
|
||||
if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) {
|
||||
BTM_TRACE_EVENT ("btm_sec_pin_code_request going for callback\n");
|
||||
|
||||
btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
|
||||
if (p_cb->api.p_pin_callback) {
|
||||
(*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
|
||||
(p_dev_rec->p_cur_service == NULL) ? FALSE
|
||||
: (p_dev_rec->p_cur_service->security_flags
|
||||
& BTM_SEC_IN_MIN_16_DIGIT_PIN));
|
||||
}
|
||||
} else {
|
||||
BTM_TRACE_EVENT ("btm_sec_pin_code_request going for remote name\n");
|
||||
|
||||
/* We received PIN code request for the device with unknown name */
|
||||
/* it is not user friendly just to ask for the PIN without name */
|
||||
/* try to get name at first */
|
||||
if (!btsnd_hcic_rmt_name_req (p_dev_rec->bd_addr,
|
||||
HCI_PAGE_SCAN_REP_MODE_R1,
|
||||
HCI_MANDATARY_PAGE_SCAN_MODE, 0)) {
|
||||
p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
|
||||
p_dev_rec->sec_bd_name[0] = 'f';
|
||||
p_dev_rec->sec_bd_name[1] = '0';
|
||||
BTM_TRACE_ERROR ("can not send rmt_name_req?? fake a name and call callback\n");
|
||||
|
||||
btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
|
||||
if (p_cb->api.p_pin_callback)
|
||||
(*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class,
|
||||
p_dev_rec->sec_bd_name, (p_dev_rec->p_cur_service == NULL) ? FALSE
|
||||
: (p_dev_rec->p_cur_service->security_flags
|
||||
& BTM_SEC_IN_MIN_16_DIGIT_PIN));
|
||||
}
|
||||
BTM_TRACE_EVENT ("btm_sec_pin_code_request going for callback\n");
|
||||
btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
|
||||
if (p_cb->api.p_pin_callback) {
|
||||
(*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
|
||||
(p_dev_rec->p_cur_service == NULL) ? FALSE
|
||||
: (p_dev_rec->p_cur_service->security_flags
|
||||
& BTM_SEC_IN_MIN_16_DIGIT_PIN));
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -489,6 +489,7 @@ typedef struct {
|
||||
tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */
|
||||
tBTM_SEC_BLE_KEYS keys; /* LE device security info in slave rode */
|
||||
bool skip_update_conn_param; /* skip update connection paraams or not*/
|
||||
UINT16 auth_mode; /* Authentication mode */
|
||||
#endif
|
||||
#if (BLE_PRIVACY_SPT == TRUE)
|
||||
tBLE_ADDR_TYPE current_addr_type; /* current adv addr type*/
|
||||
|
@ -188,6 +188,8 @@ void gatt_free(void)
|
||||
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
for (i = 0; i < GATT_MAX_SR_PROFILES; i++) {
|
||||
gatt_remove_an_item_from_list(&gatt_cb.hdl_list_info, &gatt_cb.hdl_list[i]);
|
||||
gatt_free_attr_value_buffer(&gatt_cb.hdl_list[i]);
|
||||
gatt_free_hdl_buffer(&gatt_cb.hdl_list[i]);
|
||||
}
|
||||
#endif /* #if (GATTS_INCLUDED == TRUE) */
|
||||
|
@ -1595,8 +1595,10 @@ void gatts_process_value_conf(tGATT_TCB *p_tcb, UINT8 op_code)
|
||||
if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle) {
|
||||
trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
|
||||
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_rcb->gatt_if);
|
||||
tGATTS_DATA p_data = {0};
|
||||
p_data.handle = handle;
|
||||
gatt_sr_send_req_callback(conn_id,
|
||||
trans_id, GATTS_REQ_TYPE_CONF, (tGATTS_DATA *)&handle);
|
||||
trans_id, GATTS_REQ_TYPE_CONF, &p_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -903,13 +903,14 @@ void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn
|
||||
** bd_name - Name of the peer device. NULL if unknown.
|
||||
** dev_type - Remote device's device type.
|
||||
** addr_type - LE device address type.
|
||||
** auth_mode - auth mode
|
||||
**
|
||||
** Returns TRUE if added OK, else FALSE
|
||||
**
|
||||
*******************************************************************************/
|
||||
//extern
|
||||
BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name,
|
||||
tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type);
|
||||
tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type, UINT32 auth_mode);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
@ -51,6 +51,7 @@
|
||||
#define SLIP_DYNAMIC_MEMORY TRUE
|
||||
#define LLCP_DYNAMIC_MEMORY TRUE
|
||||
#define BTC_SBC_DEC_DYNAMIC_MEMORY TRUE
|
||||
#define BTC_SBC_ENC_DYNAMIC_MEMORY TRUE
|
||||
|
||||
#else /* #if CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY */
|
||||
|
||||
@ -79,6 +80,7 @@
|
||||
#define SLIP_DYNAMIC_MEMORY FALSE
|
||||
#define LLCP_DYNAMIC_MEMORY FALSE
|
||||
#define BTC_SBC_DEC_DYNAMIC_MEMORY FALSE
|
||||
#define BTC_SBC_ENC_DYNAMIC_MEMORY FALSE
|
||||
|
||||
#endif /* #if CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY */
|
||||
/****************************************************************************
|
||||
|
@ -1845,7 +1845,7 @@ BOOLEAN L2CA_CheckIsCongest(UINT16 fixed_cid, UINT16 handle)
|
||||
tL2C_LCB *p_lcb;
|
||||
p_lcb = l2cu_find_lcb_by_handle(handle);
|
||||
|
||||
if (p_lcb != NULL) {
|
||||
if (p_lcb != NULL && p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] != NULL) {
|
||||
return p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent;
|
||||
}
|
||||
|
||||
|
@ -813,17 +813,17 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb)
|
||||
memcpy(peer_addr, p_dev_rec->ble.current_addr, 6);
|
||||
} else {
|
||||
/* find security device information but not find the real address information
|
||||
* This state may be directly open whithout scanning. In this case, you must
|
||||
* This state may be directly open without scanning. In this case, you must
|
||||
* use the current adv address of the device to open*/
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//not find security device information, We think this is a new device, connect directly
|
||||
}
|
||||
|
||||
/* It will cause that scanner doesn't send scan request to advertiser
|
||||
* which has sent IRK to us and we have stored the IRK in controller.
|
||||
* It is a design problem of hardware. The temporal solution is not to
|
||||
* send the key to the controller and then resolve the random address in host.
|
||||
* It is a hardware limitation. The preliminary solution is not to
|
||||
* send key to the controller, but to resolve the random address in host.
|
||||
* so we need send the real address information to controller. */
|
||||
/*
|
||||
if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
|
||||
|
@ -596,6 +596,7 @@ void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
}
|
||||
reason = SMP_PAIR_AUTH_FAIL;
|
||||
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -624,7 +625,7 @@ void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) {
|
||||
auth |= SMP_AUTH_GEN_BOND;
|
||||
}
|
||||
p_cb->auth_mode = auth;
|
||||
p_cb->auth_mode = auth;
|
||||
if (p_cb->accept_specified_sec_auth) {
|
||||
if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) {
|
||||
SMP_TRACE_ERROR("%s pairing failed - master requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x",
|
||||
@ -634,6 +635,7 @@ void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
}
|
||||
reason = SMP_PAIR_AUTH_FAIL;
|
||||
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1363,7 +1365,6 @@ void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
{
|
||||
uint8_t reason = SMP_PAIR_AUTH_FAIL;
|
||||
|
||||
SMP_TRACE_DEBUG("%s\n", __func__);
|
||||
if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
|
||||
/* pairing started by local (slave) Security Request */
|
||||
@ -1395,6 +1396,7 @@ void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
}
|
||||
reason = SMP_PAIR_AUTH_FAIL;
|
||||
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -964,7 +964,7 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
|
||||
tSMP_EVT_DATA evt_data = {0};
|
||||
tSMP_CALLBACK *p_callback = p_cb->p_callback;
|
||||
BD_ADDR pairing_bda;
|
||||
tBTM_SEC_DEV_REC *p_rec;
|
||||
tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda);
|
||||
|
||||
SMP_TRACE_DEBUG ("smp_proc_pairing_cmpl \n");
|
||||
|
||||
@ -973,7 +973,14 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
|
||||
evt_data.cmplt.auth_mode = 0;
|
||||
if (p_cb->status == SMP_SUCCESS) {
|
||||
evt_data.cmplt.sec_level = p_cb->sec_level;
|
||||
evt_data.cmplt.auth_mode = p_cb->auth_mode;
|
||||
if (p_cb->auth_mode) { // the first encryption
|
||||
evt_data.cmplt.auth_mode = p_cb->auth_mode;
|
||||
if (p_rec) {
|
||||
p_rec->ble.auth_mode = p_cb->auth_mode;
|
||||
}
|
||||
} else if (p_rec) {
|
||||
evt_data.cmplt.auth_mode = p_rec->ble.auth_mode;
|
||||
}
|
||||
}
|
||||
|
||||
evt_data.cmplt.is_pair_cancel = FALSE;
|
||||
@ -990,7 +997,6 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
|
||||
memcpy (pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN);
|
||||
|
||||
if (p_cb->role == HCI_ROLE_SLAVE) {
|
||||
p_rec = btm_find_dev (p_cb->pairing_bda);
|
||||
if(p_rec && p_rec->ble.skip_update_conn_param) {
|
||||
//clear flag
|
||||
p_rec->ble.skip_update_conn_param = false;
|
||||
|
@ -65,7 +65,7 @@
|
||||
/* Sleep mode */
|
||||
#define BTDM_MODEM_SLEEP_MODE_NONE (0)
|
||||
#define BTDM_MODEM_SLEEP_MODE_ORIG (1)
|
||||
#define BTDM_MODEM_SLEEP_MODE_EVED (2)
|
||||
#define BTDM_MODEM_SLEEP_MODE_EVED (2) // sleep mode for BLE controller, used only for internal test.
|
||||
|
||||
/* Low Power Clock Selection */
|
||||
#define BTDM_LPCLK_SEL_XTAL (0)
|
||||
@ -73,8 +73,9 @@
|
||||
#define BTDM_LPCLK_SEL_RTC_SLOW (2)
|
||||
#define BTDM_LPCLK_SEL_8M (3)
|
||||
|
||||
/* Sleep duration */
|
||||
#define BTDM_MIN_SLEEP_DURATION (20)
|
||||
/* Sleep and wakeup interval control */
|
||||
#define BTDM_MIN_SLEEP_DURATION (12) // threshold of interval in slots to allow to fall into modem sleep
|
||||
#define BTDM_MODEM_WAKE_UP_DELAY (4) // delay in slots of modem wake up procedure, including re-enable PHY/RF
|
||||
|
||||
#define BT_DEBUG(...)
|
||||
#define BT_API_CALL_CHECK(info, api_call, ret) \
|
||||
@ -159,8 +160,11 @@ struct osi_funcs_t {
|
||||
uint32_t (* _btdm_lpcycles_2_us)(uint32_t cycles);
|
||||
uint32_t (* _btdm_us_2_lpcycles)(uint32_t us);
|
||||
bool (* _btdm_sleep_check_duration)(uint32_t *slot_cnt);
|
||||
void (* _btdm_sleep_enter)(void);
|
||||
void (* _btdm_sleep_exit)(void); /* called from ISR */
|
||||
void (* _btdm_sleep_enter_phase1)(uint32_t lpcycles); /* called when interrupt is disabled */
|
||||
void (* _btdm_sleep_enter_phase2)(void);
|
||||
void (* _btdm_sleep_exit_phase1)(void); /* called from ISR */
|
||||
void (* _btdm_sleep_exit_phase2)(void); /* called from ISR */
|
||||
void (* _btdm_sleep_exit_phase3)(void); /* called from task */
|
||||
uint32_t _magic;
|
||||
};
|
||||
|
||||
@ -179,7 +183,7 @@ extern int btdm_controller_enable(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);
|
||||
extern void btdm_rf_bb_init_phase2(void); // shall be called after PHY/RF is enabled
|
||||
/* Sleep */
|
||||
extern void btdm_controller_enable_sleep(bool enable);
|
||||
extern void btdm_controller_set_sleep_mode(uint8_t mode);
|
||||
@ -255,8 +259,10 @@ static int IRAM_ATTR rand_wrapper(void);
|
||||
static uint32_t IRAM_ATTR btdm_lpcycles_2_us(uint32_t cycles);
|
||||
static uint32_t IRAM_ATTR btdm_us_2_lpcycles(uint32_t us);
|
||||
static bool IRAM_ATTR btdm_sleep_check_duration(uint32_t *slot_cnt);
|
||||
static void IRAM_ATTR btdm_sleep_enter_wrapper(void);
|
||||
static void IRAM_ATTR btdm_sleep_exit_wrapper(void);
|
||||
static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles);
|
||||
static void btdm_sleep_enter_phase2_wrapper(void);
|
||||
static void IRAM_ATTR btdm_sleep_exit_phase1_wrapper(void);
|
||||
static void btdm_sleep_exit_phase3_wrapper(void);
|
||||
|
||||
/* Local variable definition
|
||||
***************************************************************************
|
||||
@ -299,8 +305,11 @@ static const struct osi_funcs_t osi_funcs_ro = {
|
||||
._btdm_lpcycles_2_us = btdm_lpcycles_2_us,
|
||||
._btdm_us_2_lpcycles = btdm_us_2_lpcycles,
|
||||
._btdm_sleep_check_duration = btdm_sleep_check_duration,
|
||||
._btdm_sleep_enter = btdm_sleep_enter_wrapper,
|
||||
._btdm_sleep_exit = btdm_sleep_exit_wrapper,
|
||||
._btdm_sleep_enter_phase1 = btdm_sleep_enter_phase1_wrapper,
|
||||
._btdm_sleep_enter_phase2 = btdm_sleep_enter_phase2_wrapper,
|
||||
._btdm_sleep_exit_phase1 = btdm_sleep_exit_phase1_wrapper,
|
||||
._btdm_sleep_exit_phase2 = NULL,
|
||||
._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper,
|
||||
._magic = OSI_MAGIC_VALUE,
|
||||
};
|
||||
|
||||
@ -325,27 +334,42 @@ SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_BSS_START, SOC_MEM_BT_BSS_END,
|
||||
SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_MISC_START, SOC_MEM_BT_MISC_END, rom_bt_misc);
|
||||
SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_DATA_START, SOC_MEM_BT_DATA_END, rom_bt_data);
|
||||
|
||||
static struct osi_funcs_t *osi_funcs_p;
|
||||
static DRAM_ATTR struct osi_funcs_t *osi_funcs_p;
|
||||
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
static btdm_queue_item_t btdm_queue_table[BTDM_MAX_QUEUE_NUM];
|
||||
SemaphoreHandle_t btdm_queue_table_mux = NULL;
|
||||
static DRAM_ATTR btdm_queue_item_t btdm_queue_table[BTDM_MAX_QUEUE_NUM];
|
||||
static DRAM_ATTR SemaphoreHandle_t btdm_queue_table_mux = NULL;
|
||||
#endif /* #if CONFIG_SPIRAM_USE_MALLOC */
|
||||
|
||||
/* Static variable declare */
|
||||
static bool btdm_bb_init_flag = false;
|
||||
static esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
|
||||
// timestamp when PHY/RF was switched on
|
||||
static DRAM_ATTR int64_t s_time_phy_rf_just_enabled = 0;
|
||||
static DRAM_ATTR esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
|
||||
|
||||
static portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
static DRAM_ATTR portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
// measured average low power clock period in micro seconds
|
||||
static uint32_t btdm_lpcycle_us = 0;
|
||||
static uint8_t btdm_lpcycle_us_frac = 0; // number of fractional bit for btdm_lpcycle_us
|
||||
static DRAM_ATTR uint32_t btdm_lpcycle_us = 0;
|
||||
static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; // number of fractional bit for btdm_lpcycle_us
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
static esp_pm_lock_handle_t s_pm_lock;
|
||||
static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr;
|
||||
static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock;
|
||||
static DRAM_ATTR esp_pm_lock_handle_t s_light_sleep_pm_lock; // pm_lock to prevent light sleep due to incompatibility currently
|
||||
static DRAM_ATTR QueueHandle_t s_pm_lock_sem = NULL;
|
||||
#endif
|
||||
|
||||
static inline void btdm_check_and_init_bb(void)
|
||||
{
|
||||
/* init BT-BB if PHY/RF has been switched off since last BT-BB init */
|
||||
int64_t latest_ts = esp_phy_rf_get_on_ts();
|
||||
if (latest_ts != s_time_phy_rf_just_enabled ||
|
||||
s_time_phy_rf_just_enabled == 0) {
|
||||
btdm_rf_bb_init_phase2();
|
||||
s_time_phy_rf_just_enabled = latest_ts;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
static bool btdm_queue_generic_register(const btdm_queue_item_t *queue)
|
||||
{
|
||||
@ -728,7 +752,7 @@ static int IRAM_ATTR rand_wrapper(void)
|
||||
|
||||
static uint32_t IRAM_ATTR btdm_lpcycles_2_us(uint32_t cycles)
|
||||
{
|
||||
// The number of lp cycles should not lead to overflow. Thrs: 100s (for 32kHz freq)
|
||||
// The number of lp cycles should not lead to overflow. Thrs: 100s
|
||||
// clock measurement is conducted
|
||||
uint64_t us = (uint64_t)btdm_lpcycle_us * cycles;
|
||||
us = (us + (1 << (btdm_lpcycle_us_frac - 1))) >> btdm_lpcycle_us_frac;
|
||||
@ -753,16 +777,41 @@ static bool IRAM_ATTR btdm_sleep_check_duration(uint32_t *slot_cnt)
|
||||
if (*slot_cnt < BTDM_MIN_SLEEP_DURATION) {
|
||||
return false;
|
||||
}
|
||||
/* wake up 3 slots in advance */
|
||||
*slot_cnt = *slot_cnt -3;
|
||||
/* wake up in advance considering the delay in enabling PHY/RF */
|
||||
*slot_cnt -= BTDM_MODEM_WAKE_UP_DELAY;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR btdm_sleep_enter_wrapper(void)
|
||||
static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles)
|
||||
{
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
// start a timer to wake up and acquire the pm_lock before modem_sleep awakes
|
||||
uint32_t us_to_sleep = btdm_lpcycles_2_us(lpcycles);
|
||||
|
||||
#define BTDM_MIN_TIMER_UNCERTAINTY_US (1800)
|
||||
assert(us_to_sleep > BTDM_MIN_TIMER_UNCERTAINTY_US);
|
||||
// allow a maximum time uncertainty to be about 488ppm(1/2048) at least as clock drift
|
||||
// and set the timer in advance
|
||||
uint32_t uncertainty = (us_to_sleep >> 11);
|
||||
if (uncertainty < BTDM_MIN_TIMER_UNCERTAINTY_US) {
|
||||
uncertainty = BTDM_MIN_TIMER_UNCERTAINTY_US;
|
||||
}
|
||||
|
||||
if (esp_timer_start_once(s_btdm_slp_tmr, us_to_sleep - uncertainty) != ESP_OK) {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "timer start failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void btdm_sleep_enter_phase2_wrapper(void)
|
||||
{
|
||||
if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG) {
|
||||
esp_modem_sleep_enter(MODEM_BLE_MODULE);
|
||||
esp_modem_sleep_enter(MODEM_CLASSIC_BT_MODULE);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(s_pm_lock);
|
||||
semphr_give_wrapper(s_pm_lock_sem);
|
||||
#endif
|
||||
} else if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_EVED) {
|
||||
esp_modem_sleep_enter(MODEM_BLE_MODULE);
|
||||
// pause bluetooth baseband
|
||||
@ -770,11 +819,24 @@ static void IRAM_ATTR btdm_sleep_enter_wrapper(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR btdm_sleep_exit_wrapper(void)
|
||||
static void IRAM_ATTR btdm_sleep_exit_phase1_wrapper(void)
|
||||
{
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (semphr_take_from_isr_wrapper(s_pm_lock_sem, NULL) == pdTRUE) {
|
||||
esp_pm_lock_acquire(s_pm_lock);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void btdm_sleep_exit_phase3_wrapper(void)
|
||||
{
|
||||
if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG) {
|
||||
esp_modem_sleep_exit(MODEM_BLE_MODULE);
|
||||
esp_modem_sleep_exit(MODEM_CLASSIC_BT_MODULE);
|
||||
btdm_check_and_init_bb();
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_timer_stop(s_btdm_slp_tmr);
|
||||
#endif
|
||||
} else if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_EVED) {
|
||||
// resume bluetooth baseband
|
||||
periph_module_enable(PERIPH_BT_BASEBAND_MODULE);
|
||||
@ -782,6 +844,15 @@ static void IRAM_ATTR btdm_sleep_exit_wrapper(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
static void IRAM_ATTR btdm_slp_tmr_callback(void *arg)
|
||||
{
|
||||
if (semphr_take_wrapper(s_pm_lock_sem, 0) == pdTRUE) {
|
||||
esp_pm_lock_acquire(s_pm_lock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool esp_vhci_host_check_send_available(void)
|
||||
{
|
||||
return API_vhci_host_check_send_available();
|
||||
@ -790,6 +861,12 @@ bool esp_vhci_host_check_send_available(void)
|
||||
void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!btdm_power_state_active()) {
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (semphr_take_wrapper(s_pm_lock_sem, 0)) {
|
||||
esp_pm_lock_acquire(s_pm_lock);
|
||||
}
|
||||
esp_timer_stop(s_btdm_slp_tmr);
|
||||
#endif
|
||||
btdm_wakeup_request();
|
||||
}
|
||||
API_vhci_host_send_packet(data, len);
|
||||
@ -942,7 +1019,7 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode)
|
||||
|
||||
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
{
|
||||
BaseType_t ret;
|
||||
esp_err_t err;
|
||||
uint32_t btdm_cfg_mask = 0;
|
||||
|
||||
osi_funcs_p = (struct osi_funcs_t *)malloc_internal_wrapper(sizeof(struct osi_funcs_t));
|
||||
@ -983,27 +1060,39 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_LOGI(BTDM_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version());
|
||||
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
btdm_queue_table_mux = xSemaphoreCreateMutex();
|
||||
if (btdm_queue_table == NULL) {
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_delete(s_pm_lock);
|
||||
s_pm_lock = NULL;
|
||||
#endif
|
||||
if (btdm_queue_table_mux == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) {
|
||||
goto error;
|
||||
}
|
||||
if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) {
|
||||
goto error;
|
||||
}
|
||||
esp_timer_create_args_t create_args = {
|
||||
.callback = btdm_slp_tmr_callback,
|
||||
.arg = NULL,
|
||||
.name = "btSlp"
|
||||
};
|
||||
if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
s_pm_lock_sem = semphr_create_wrapper(1, 0);
|
||||
if (s_pm_lock_sem == NULL) {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
btdm_controller_mem_init();
|
||||
|
||||
periph_module_enable(PERIPH_BT_MODULE);
|
||||
@ -1015,10 +1104,10 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
bool set_div_ret = false;
|
||||
#if CONFIG_BTDM_LPCLK_SEL_MAIN_XTAL
|
||||
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL);
|
||||
set_div_ret = btdm_lpclk_set_div(rtc_clk_xtal_freq_get() * 32 - 1);
|
||||
set_div_ret = btdm_lpclk_set_div(rtc_clk_xtal_freq_get() * 2 - 1);
|
||||
assert(select_src_ret && set_div_ret);
|
||||
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
|
||||
btdm_lpcycle_us = 32 << btdm_lpcycle_us_frac;
|
||||
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
|
||||
#elif CONFIG_BTDM_LPCLK_SEL_EXT_32K_XTAL
|
||||
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL32K);
|
||||
set_div_ret = btdm_lpclk_set_div(0);
|
||||
@ -1036,17 +1125,35 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
|
||||
btdm_cfg_mask = btdm_config_mask_load();
|
||||
|
||||
ret = btdm_controller_init(btdm_cfg_mask, cfg);
|
||||
if (ret) {
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_delete(s_pm_lock);
|
||||
s_pm_lock = NULL;
|
||||
#endif
|
||||
return ESP_ERR_NO_MEM;
|
||||
if (btdm_controller_init(btdm_cfg_mask, cfg) != 0) {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
error:
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (s_light_sleep_pm_lock != NULL) {
|
||||
esp_pm_lock_delete(s_light_sleep_pm_lock);
|
||||
s_light_sleep_pm_lock = NULL;
|
||||
}
|
||||
if (s_pm_lock != NULL) {
|
||||
esp_pm_lock_delete(s_pm_lock);
|
||||
s_pm_lock = NULL;
|
||||
}
|
||||
if (s_btdm_slp_tmr != NULL) {
|
||||
esp_timer_delete(s_btdm_slp_tmr);
|
||||
s_btdm_slp_tmr = NULL;
|
||||
}
|
||||
if (s_pm_lock_sem) {
|
||||
semphr_delete_wrapper(s_pm_lock_sem);
|
||||
s_pm_lock_sem = NULL;
|
||||
}
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_bt_controller_deinit(void)
|
||||
@ -1059,6 +1166,18 @@ esp_err_t esp_bt_controller_deinit(void)
|
||||
|
||||
periph_module_disable(PERIPH_BT_MODULE);
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_delete(s_light_sleep_pm_lock);
|
||||
s_light_sleep_pm_lock = NULL;
|
||||
esp_pm_lock_delete(s_pm_lock);
|
||||
s_pm_lock = NULL;
|
||||
esp_timer_stop(s_btdm_slp_tmr);
|
||||
esp_timer_delete(s_btdm_slp_tmr);
|
||||
s_btdm_slp_tmr = NULL;
|
||||
semphr_delete_wrapper(s_pm_lock_sem);
|
||||
s_pm_lock_sem = NULL;
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
vSemaphoreDelete(btdm_queue_table_mux);
|
||||
btdm_queue_table_mux = NULL;
|
||||
@ -1072,10 +1191,6 @@ esp_err_t esp_bt_controller_deinit(void)
|
||||
|
||||
btdm_lpcycle_us = 0;
|
||||
btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_NONE);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_delete(s_pm_lock);
|
||||
s_pm_lock = NULL;
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -1094,6 +1209,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_acquire(s_light_sleep_pm_lock);
|
||||
esp_pm_lock_acquire(s_pm_lock);
|
||||
#endif
|
||||
|
||||
@ -1117,10 +1233,8 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
|
||||
btdm_controller_enable_sleep(true);
|
||||
}
|
||||
|
||||
if (btdm_bb_init_flag == false) {
|
||||
btdm_bb_init_flag = true;
|
||||
btdm_rf_bb_init(); /* only initialise once */
|
||||
}
|
||||
// inititalize bluetooth baseband
|
||||
btdm_check_and_init_bb();
|
||||
|
||||
ret = btdm_controller_enable(mode);
|
||||
if (ret) {
|
||||
@ -1133,6 +1247,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
|
||||
}
|
||||
esp_phy_rf_deinit(PHY_BT_MODULE);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(s_light_sleep_pm_lock);
|
||||
esp_pm_lock_release(s_pm_lock);
|
||||
#endif
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
@ -1173,6 +1288,7 @@ esp_err_t esp_bt_controller_disable(void)
|
||||
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(s_light_sleep_pm_lock);
|
||||
esp_pm_lock_release(s_pm_lock);
|
||||
#endif
|
||||
|
||||
|
@ -326,8 +326,12 @@ bool esp_vhci_host_check_send_available(void);
|
||||
|
||||
/** @brief esp_vhci_host_send_packet
|
||||
* host send packet to controller
|
||||
*
|
||||
* Should not call this function from within a critical section
|
||||
* or when the scheduler is suspended.
|
||||
*
|
||||
* @param data the packet point
|
||||
*,@param len the packet length
|
||||
* @param len the packet length
|
||||
*/
|
||||
void esp_vhci_host_send_packet(uint8_t *data, uint16_t len);
|
||||
|
||||
@ -405,7 +409,6 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode);
|
||||
*
|
||||
* For ORIG mode:
|
||||
* Bluetooth modem sleep is enabled in controller start up by default if CONFIG_BTDM_CONTROLLER_MODEM_SLEEP is set and "ORIG mode" is selected. In ORIG modem sleep mode, bluetooth controller will switch off some components and pause to work every now and then, if there is no event to process; and wakeup according to the scheduled interval and resume the work. It can also wakeup earlier upon external request using function "esp_bt_controller_wakeup_request".
|
||||
* Note that currently there is problem in the combination use of bluetooth modem sleep and Dynamic Frequency Scaling(DFS). So do not enable DFS if bluetooth modem sleep is in use.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
@ -454,11 +457,11 @@ void esp_bt_controller_wakeup_request(void);
|
||||
|
||||
/**
|
||||
* @brief Manually clear scan duplicate list
|
||||
*
|
||||
*
|
||||
* Note that scan duplicate list will be automatically cleared when the maximum amount of device in the filter is reached
|
||||
* the amount of device in the filter can be configured in menuconfig.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - other : failed
|
||||
|
Submodule components/bt/lib updated: 16f95952ef...a6f784dbb8
@ -41,8 +41,10 @@ config SPI_MASTER_ISR_IN_IRAM
|
||||
bool "Place SPI master ISR function into IRAM"
|
||||
default y
|
||||
help
|
||||
Place the SPI master ISR in to IRAM to avoid possibly cache miss, or
|
||||
being disabled during flash writing access.
|
||||
Place the SPI master ISR in to IRAM to avoid possible cache miss.
|
||||
|
||||
Also you can forbid the ISR being disabled during flash writing
|
||||
access, by add ESP_INTR_FLAG_IRAM when initializing the driver.
|
||||
|
||||
config SPI_SLAVE_IN_IRAM
|
||||
bool "Place transmitting functions of SPI slave into IRAM"
|
||||
@ -61,8 +63,10 @@ config SPI_SLAVE_ISR_IN_IRAM
|
||||
bool "Place SPI slave ISR function into IRAM"
|
||||
default y
|
||||
help
|
||||
Place the SPI slave ISR in to IRAM to avoid possibly cache miss, or
|
||||
being disabled during flash writing access.
|
||||
Place the SPI slave ISR in to IRAM to avoid possible cache miss.
|
||||
|
||||
Also you can forbid the ISR being disabled during flash writing
|
||||
access, by add ESP_INTR_FLAG_IRAM when initializing the driver.
|
||||
|
||||
endmenu # SPI Configuration
|
||||
|
||||
|
@ -79,6 +79,9 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
|
||||
#define I2C_SLAVE_SDA_HOLD_DEFAULT (10) /* I2C slave hold time after scl negative edge default value */
|
||||
#define I2C_MASTER_TOUT_CNUM_DEFAULT (8) /* I2C master timeout cycle number of I2C clock, after which the timeout interrupt will be triggered */
|
||||
#define I2C_ACKERR_CNT_MAX (10)
|
||||
#define I2C_FILTER_CYC_NUM_DEF (7) /* The number of apb cycles filtered by default*/
|
||||
#define I2C_CLR_BUS_SCL_NUM (9)
|
||||
#define I2C_CLR_BUS_HALF_PERIOD_US (5)
|
||||
|
||||
typedef struct {
|
||||
uint8_t byte_num; /*!< cmd byte number */
|
||||
@ -524,7 +527,9 @@ esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode,
|
||||
static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate
|
||||
int sda_in_sig = 0, scl_in_sig = 0;
|
||||
int i = 0;
|
||||
if (i2c_num == I2C_NUM_0) {
|
||||
sda_in_sig = I2CEXT0_SDA_IN_IDX;
|
||||
scl_in_sig = I2CEXT0_SCL_IN_IDX;
|
||||
@ -535,19 +540,27 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
||||
int scl_io = GPIO.func_in_sel_cfg[scl_in_sig].func_sel;
|
||||
int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel;
|
||||
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK((GPIO_IS_VALID_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
// We do not check whether the SDA line is low
|
||||
// because after some serious interference, the bus may keep high all the time and the i2c bus is out of service.
|
||||
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD);
|
||||
gpio_set_direction(sda_io, GPIO_MODE_OUTPUT_OD);
|
||||
gpio_set_level(scl_io, 1);
|
||||
gpio_set_direction(sda_io, GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
// If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA.
|
||||
// The only bit during the 9 clock cycles of a READ byte the MASTER(ESP32) is guaranteed control over is during the ACK bit
|
||||
// period. If the slave is sending a stream of ZERO bytes, it will only release SDA during the ACK bit period.
|
||||
// So, this reset code needs to synchronize the bit stream with, Either, the ACK bit, Or a 1 bit to correctly generate
|
||||
// a STOP condition.
|
||||
gpio_set_level(scl_io, 0);
|
||||
gpio_set_level(sda_io, 1);
|
||||
gpio_set_level(sda_io, 0);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
gpio_set_level(scl_io, 0);
|
||||
ets_delay_us(scl_half_period);
|
||||
while(!gpio_get_level(sda_io) && (i++ < I2C_CLR_BUS_SCL_NUM)) {
|
||||
gpio_set_level(scl_io, 1);
|
||||
ets_delay_us(scl_half_period);
|
||||
gpio_set_level(scl_io, 0);
|
||||
ets_delay_us(scl_half_period);
|
||||
}
|
||||
gpio_set_level(sda_io, 1);
|
||||
gpio_set_level(sda_io,0); // setup for STOP
|
||||
gpio_set_level(scl_io,1);
|
||||
ets_delay_us(scl_half_period);
|
||||
gpio_set_level(sda_io, 1); // STOP, SDA low -> high while SCL is HIGH
|
||||
i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -660,6 +673,8 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
|
||||
//set timing for stop signal
|
||||
I2C[i2c_num]->scl_stop_hold.time = half_cycle;
|
||||
I2C[i2c_num]->scl_stop_setup.time = half_cycle;
|
||||
//Default, we enable hardware filter
|
||||
i2c_filter_enable(i2c_num, I2C_FILTER_CYC_NUM_DEF);
|
||||
}
|
||||
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
@ -693,6 +708,28 @@ esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
I2C[i2c_num]->scl_filter_cfg.thres = cyc_num;
|
||||
I2C[i2c_num]->sda_filter_cfg.thres = cyc_num;
|
||||
I2C[i2c_num]->scl_filter_cfg.en = 1;
|
||||
I2C[i2c_num]->sda_filter_cfg.en = 1;
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_filter_disable(i2c_port_t i2c_num)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
I2C[i2c_num]->scl_filter_cfg.en = 0;
|
||||
I2C[i2c_num]->sda_filter_cfg.en = 0;
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
@ -1375,4 +1412,4 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, Ti
|
||||
}
|
||||
xSemaphoreGive(p_i2c->slv_rx_mux);
|
||||
return cnt;
|
||||
}
|
||||
}
|
@ -86,6 +86,7 @@ typedef struct {
|
||||
i2s_mode_t mode; /*!< I2S Working mode*/
|
||||
uint32_t sample_rate; /*!< I2S sample rate */
|
||||
bool use_apll; /*!< I2S use APLL clock */
|
||||
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */
|
||||
int fixed_mclk; /*!< I2S fixed MLCK clock */
|
||||
} i2s_obj_t;
|
||||
|
||||
@ -502,6 +503,12 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
|
||||
// All buffers are empty. This means we have an underflow on our hands.
|
||||
if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) {
|
||||
xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken);
|
||||
// See if tx descriptor needs to be auto cleared:
|
||||
// This will avoid any kind of noise that may get introduced due to transmission
|
||||
// of previous data from tx descriptor on I2S line.
|
||||
if (p_i2s->tx_desc_auto_clear == true) {
|
||||
memset((void *) dummy, 0, p_i2s->tx->buf_size);
|
||||
}
|
||||
}
|
||||
xQueueSendFromISR(p_i2s->tx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken);
|
||||
if (p_i2s->i2s_queue) {
|
||||
@ -991,6 +998,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
|
||||
}
|
||||
|
||||
p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll;
|
||||
p_i2s_obj[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear;
|
||||
p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -420,6 +420,35 @@ esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period);
|
||||
*/
|
||||
esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period);
|
||||
|
||||
/**
|
||||
* @brief enable hardware filter on I2C bus
|
||||
* Sometimes the I2C bus is disturbed by high frequency noise(about 20ns), or the rising edge of
|
||||
* the SCL clock is very slow, these may cause the master state machine broken. enable hardware
|
||||
* filter can filter out high frequency interference and make the master more stable.
|
||||
* @note
|
||||
* Enable filter will slow the SCL clock.
|
||||
*
|
||||
* @param i2c_num I2C port number
|
||||
* @param cyc_num the APB cycles need to be filtered(0<= cyc_num <=7).
|
||||
* When the period of a pulse is less than cyc_num * APB_cycle, the I2C controller will ignore this pulse.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num);
|
||||
|
||||
/**
|
||||
* @brief disable filter on I2C bus
|
||||
*
|
||||
* @param i2c_num I2C port number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2c_filter_disable(i2c_port_t i2c_num);
|
||||
|
||||
/**
|
||||
* @brief set I2C master start signal timing
|
||||
*
|
||||
|
@ -139,6 +139,7 @@ typedef struct {
|
||||
int dma_buf_count; /*!< I2S DMA Buffer Count */
|
||||
int dma_buf_len; /*!< I2S DMA Buffer Length */
|
||||
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
|
||||
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
|
||||
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
|
||||
} i2s_config_t;
|
||||
|
||||
|
@ -87,6 +87,11 @@ typedef struct {
|
||||
int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
|
||||
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
|
||||
uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
|
||||
int intr_flags; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
|
||||
* ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
|
||||
* by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
|
||||
* the driver, and their callee functions, should be put in the IRAM.
|
||||
*/
|
||||
} spi_bus_config_t;
|
||||
|
||||
|
||||
|
@ -79,8 +79,26 @@ typedef struct {
|
||||
int spics_io_num; ///< CS GPIO pin for this device, or -1 if not used
|
||||
uint32_t flags; ///< Bitwise OR of SPI_DEVICE_* flags
|
||||
int queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_device_queue_trans but not yet finished using spi_device_get_trans_result) at the same time
|
||||
transaction_cb_t pre_cb; ///< Callback to be called before a transmission is started. This callback is called within interrupt context.
|
||||
transaction_cb_t post_cb; ///< Callback to be called after a transmission has completed. This callback is called within interrupt context.
|
||||
transaction_cb_t pre_cb; /**< Callback to be called before a transmission is started.
|
||||
*
|
||||
* This callback is called within interrupt
|
||||
* context should be in IRAM for best
|
||||
* performance, see "Transferring Speed"
|
||||
* section in the SPI Master documentation for
|
||||
* full details. If not, the callback may crash
|
||||
* during flash operation when the driver is
|
||||
* initialized with ESP_INTR_FLAG_IRAM.
|
||||
*/
|
||||
transaction_cb_t post_cb; /**< Callback to be called after a transmission has completed.
|
||||
*
|
||||
* This callback is called within interrupt
|
||||
* context should be in IRAM for best
|
||||
* performance, see "Transferring Speed"
|
||||
* section in the SPI Master documentation for
|
||||
* full details. If not, the callback may crash
|
||||
* during flash operation when the driver is
|
||||
* initialized with ESP_INTR_FLAG_IRAM.
|
||||
*/
|
||||
} spi_device_interface_config_t;
|
||||
|
||||
|
||||
|
@ -44,8 +44,26 @@ typedef struct {
|
||||
uint32_t flags; ///< Bitwise OR of SPI_SLAVE_* flags
|
||||
int queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_slave_queue_trans but not yet finished using spi_slave_get_trans_result) at the same time
|
||||
uint8_t mode; ///< SPI mode (0-3)
|
||||
slave_transaction_cb_t post_setup_cb; ///< Callback called after the SPI registers are loaded with new data
|
||||
slave_transaction_cb_t post_trans_cb; ///< Callback called after a transaction is done
|
||||
slave_transaction_cb_t post_setup_cb; /**< Callback called after the SPI registers are loaded with new data.
|
||||
*
|
||||
* This callback is called within interrupt
|
||||
* context should be in IRAM for best
|
||||
* performance, see "Transferring Speed"
|
||||
* section in the SPI Master documentation for
|
||||
* full details. If not, the callback may crash
|
||||
* during flash operation when the driver is
|
||||
* initialized with ESP_INTR_FLAG_IRAM.
|
||||
*/
|
||||
slave_transaction_cb_t post_trans_cb; /**< Callback called after a transaction is done.
|
||||
*
|
||||
* This callback is called within interrupt
|
||||
* context should be in IRAM for best
|
||||
* performance, see "Transferring Speed"
|
||||
* section in the SPI Master documentation for
|
||||
* full details. If not, the callback may crash
|
||||
* during flash operation when the driver is
|
||||
* initialized with ESP_INTR_FLAG_IRAM.
|
||||
*/
|
||||
} spi_slave_interface_config_t;
|
||||
|
||||
/**
|
||||
|
@ -233,6 +233,10 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
||||
|
||||
SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
||||
#ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
|
||||
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
|
||||
spi_chan_claimed=spicommon_periph_claim(host);
|
||||
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
@ -284,10 +288,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
||||
}
|
||||
}
|
||||
|
||||
int flags = ESP_INTR_FLAG_INTRDISABLED;
|
||||
#ifdef CONFIG_SPI_MASTER_ISR_IN_IRAM
|
||||
flags |= ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
|
||||
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void*)spihost[host], &spihost[host]->intr);
|
||||
if (err != ESP_OK) {
|
||||
ret = err;
|
||||
|
@ -109,6 +109,10 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
//We only support HSPI/VSPI, period.
|
||||
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
||||
#ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM
|
||||
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
|
||||
spi_chan_claimed=spicommon_periph_claim(host);
|
||||
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
@ -174,10 +178,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int flags = ESP_INTR_FLAG_INTRDISABLED;
|
||||
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
|
||||
flags |= ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
|
||||
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr);
|
||||
if (err != ESP_OK) {
|
||||
ret = err;
|
||||
|
@ -875,6 +875,7 @@ static void uart_rx_intr_handler_default(void *param)
|
||||
//If we fail to push data to ring buffer, we will have to stash the data, and send next time.
|
||||
//Mainly for applications that uses flow control or small ring buffer.
|
||||
if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) {
|
||||
p_uart->rx_buffer_full_flg = true;
|
||||
uart_disable_intr_mask(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M);
|
||||
if (uart_event.type == UART_PATTERN_DET) {
|
||||
if (rx_fifo_len < pat_num) {
|
||||
@ -893,7 +894,6 @@ static void uart_rx_intr_handler_default(void *param)
|
||||
}
|
||||
}
|
||||
uart_event.type = UART_BUFFER_FULL;
|
||||
p_uart->rx_buffer_full_flg = true;
|
||||
} else {
|
||||
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
|
||||
if (uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) {
|
||||
@ -1164,6 +1164,22 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t si
|
||||
return uart_tx_all(uart_num, src, size, 1, brk_len);
|
||||
}
|
||||
|
||||
static bool uart_check_buf_full(uart_port_t uart_num)
|
||||
{
|
||||
if(p_uart_obj[uart_num]->rx_buffer_full_flg) {
|
||||
BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);
|
||||
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;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait)
|
||||
{
|
||||
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
|
||||
@ -1184,8 +1200,17 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
|
||||
p_uart_obj[uart_num]->rx_ptr = data;
|
||||
p_uart_obj[uart_num]->rx_cur_remain = size;
|
||||
} else {
|
||||
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
|
||||
return copy_len;
|
||||
//When using dual cores, `rx_buffer_full_flg` may read and write on different cores at same time,
|
||||
//which may lose synchronization. So we also need to call `uart_check_buf_full` once when ringbuffer is empty
|
||||
//to solve the possible asynchronous issues.
|
||||
if(uart_check_buf_full(uart_num)) {
|
||||
//This condition will never be true if `uart_read_bytes`
|
||||
//and `uart_rx_intr_handler_default` are scheduled on the same core.
|
||||
continue;
|
||||
} else {
|
||||
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
|
||||
return copy_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(p_uart_obj[uart_num]->rx_cur_remain > length) {
|
||||
@ -1206,16 +1231,7 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
|
||||
vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_head_ptr);
|
||||
p_uart_obj[uart_num]->rx_head_ptr = NULL;
|
||||
p_uart_obj[uart_num]->rx_ptr = NULL;
|
||||
if(p_uart_obj[uart_num]->rx_buffer_full_flg) {
|
||||
BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
uart_check_buf_full(uart_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,4 +148,10 @@ else()
|
||||
if(NOT "${BUILD_TEST_COMPONENTS}" EQUAL "")
|
||||
add_definitions(-DESP_TIMER_DYNAMIC_OVERFLOW_VAL)
|
||||
endif()
|
||||
|
||||
# disable stack protection in files which are involved in initialization of that feature
|
||||
set_source_files_properties(
|
||||
stack_check.c cpu_start.c
|
||||
PROPERTIES COMPILE_FLAGS
|
||||
-fno-stack-protector)
|
||||
endif()
|
||||
|
@ -213,6 +213,29 @@ config SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
|
||||
in PSRAM instead of internal memory, and placed most of variables of lwip,net802.11,pp,bluedroid library
|
||||
to external memory defaultly.
|
||||
|
||||
choice SPIRAM_OCCUPY_SPI_HOST
|
||||
prompt "SPI host to use for 32MBit PSRAM"
|
||||
default SPIRAM_OCCUPY_VSPI_HOST
|
||||
depends on SPIRAM_SPEED_80M
|
||||
help
|
||||
When both flash and PSRAM is working under 80MHz, and the PSRAM is of type 32MBit, one of the HSPI/VSPI
|
||||
host will be used to output the clock. Select which one to use here.
|
||||
|
||||
config SPIRAM_OCCUPY_HSPI_HOST
|
||||
bool "HSPI host (SPI2)"
|
||||
config SPIRAM_OCCUPY_VSPI_HOST
|
||||
bool "VSPI host (SPI3)"
|
||||
endchoice
|
||||
|
||||
config PICO_PSRAM_CS_IO
|
||||
int "PSRAM CS IO for ESP32-PICO chip"
|
||||
depends on SPIRAM_SUPPORT
|
||||
range 0 33
|
||||
default 10
|
||||
help
|
||||
When ESP32-PICO chip connect a external psram, the clock IO and data IO is fixed, but the CS IO can be
|
||||
any unused GPIO, user can config it based on hardware design.
|
||||
|
||||
endmenu
|
||||
|
||||
config MEMMAP_TRACEMEM
|
||||
|
@ -124,6 +124,7 @@ void IRAM_ATTR call_start_cpu0()
|
||||
RESET_REASON rst_reas[2];
|
||||
#endif
|
||||
cpu_configure_region_protection();
|
||||
cpu_init_memctl();
|
||||
|
||||
//Move exception vectors to IRAM
|
||||
asm volatile (\
|
||||
@ -249,6 +250,7 @@ void IRAM_ATTR call_start_cpu1()
|
||||
|
||||
ets_set_appcpu_boot_addr(0);
|
||||
cpu_configure_region_protection();
|
||||
cpu_init_memctl();
|
||||
|
||||
#if CONFIG_CONSOLE_UART_NONE
|
||||
ets_install_putc1(NULL);
|
||||
|
@ -83,10 +83,13 @@ static esp_timer_handle_t s_timer_in_callback;
|
||||
static TaskHandle_t s_timer_task;
|
||||
// counting semaphore used to notify the timer task from ISR
|
||||
static SemaphoreHandle_t s_timer_semaphore;
|
||||
// mutex which protects timers from deletion during callback execution
|
||||
static SemaphoreHandle_t s_timer_delete_mutex;
|
||||
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
// memory for s_timer_semaphore
|
||||
// memory for s_timer_semaphore and s_timer_delete_mutex
|
||||
static StaticQueue_t s_timer_semaphore_memory;
|
||||
static StaticQueue_t s_timer_delete_mutex_memory;
|
||||
#endif
|
||||
|
||||
// lock protecting s_timers, s_inactive_timers, s_timer_in_callback
|
||||
@ -154,19 +157,21 @@ esp_err_t IRAM_ATTR esp_timer_stop(esp_timer_handle_t timer)
|
||||
|
||||
esp_err_t esp_timer_delete(esp_timer_handle_t timer)
|
||||
{
|
||||
if (timer == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (timer_armed(timer)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
xSemaphoreTakeRecursive(s_timer_delete_mutex, portMAX_DELAY);
|
||||
#if WITH_PROFILING
|
||||
if (timer == s_timer_in_callback) {
|
||||
s_timer_in_callback = NULL;
|
||||
}
|
||||
timer_remove_inactive(timer);
|
||||
#endif
|
||||
if (timer == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
free(timer);
|
||||
xSemaphoreGiveRecursive(s_timer_delete_mutex);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -261,6 +266,7 @@ static void timer_process_alarm(esp_timer_dispatch_t dispatch_method)
|
||||
/* unused, provision to allow running callbacks from ISR */
|
||||
(void) dispatch_method;
|
||||
|
||||
xSemaphoreTakeRecursive(s_timer_delete_mutex, portMAX_DELAY);
|
||||
timer_list_lock();
|
||||
uint64_t now = esp_timer_impl_get_time();
|
||||
esp_timer_handle_t it = LIST_FIRST(&s_timers);
|
||||
@ -301,6 +307,7 @@ static void timer_process_alarm(esp_timer_dispatch_t dispatch_method)
|
||||
esp_timer_impl_set_alarm(first->alarm);
|
||||
}
|
||||
timer_list_unlock();
|
||||
xSemaphoreGiveRecursive(s_timer_delete_mutex);
|
||||
}
|
||||
|
||||
static void timer_task(void* arg)
|
||||
@ -332,6 +339,7 @@ static IRAM_ATTR bool is_initialized()
|
||||
|
||||
esp_err_t esp_timer_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
if (is_initialized()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
@ -343,27 +351,50 @@ esp_err_t esp_timer_init(void)
|
||||
s_timer_semaphore = xSemaphoreCreateCounting(TIMER_EVENT_QUEUE_SIZE, 0);
|
||||
#endif
|
||||
if (!s_timer_semaphore) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
memset(&s_timer_delete_mutex_memory, 0, sizeof(StaticQueue_t));
|
||||
s_timer_delete_mutex = xSemaphoreCreateRecursiveMutexStatic(&s_timer_delete_mutex_memory);
|
||||
#else
|
||||
s_timer_delete_mutex = xSemaphoreCreateRecursiveMutex();
|
||||
#endif
|
||||
if (!s_timer_delete_mutex) {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
int ret = xTaskCreatePinnedToCore(&timer_task, "esp_timer",
|
||||
ESP_TASK_TIMER_STACK, NULL, ESP_TASK_TIMER_PRIO, &s_timer_task, PRO_CPU_NUM);
|
||||
if (ret != pdPASS) {
|
||||
vSemaphoreDelete(s_timer_semaphore);
|
||||
s_timer_semaphore = NULL;
|
||||
return ESP_ERR_NO_MEM;
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_timer_impl_init(&timer_alarm_handler);
|
||||
err = esp_timer_impl_init(&timer_alarm_handler);
|
||||
if (err != ESP_OK) {
|
||||
vTaskDelete(s_timer_task);
|
||||
s_timer_task = NULL;
|
||||
vSemaphoreDelete(s_timer_semaphore);
|
||||
s_timer_semaphore = NULL;
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
out:
|
||||
if (s_timer_task) {
|
||||
vTaskDelete(s_timer_task);
|
||||
s_timer_task = NULL;
|
||||
}
|
||||
if (s_timer_semaphore) {
|
||||
vSemaphoreDelete(s_timer_semaphore);
|
||||
s_timer_semaphore = NULL;
|
||||
}
|
||||
if (s_timer_delete_mutex) {
|
||||
vSemaphoreDelete(s_timer_delete_mutex);
|
||||
s_timer_delete_mutex = NULL;
|
||||
}
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t esp_timer_deinit(void)
|
||||
|
@ -27,10 +27,12 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/lock.h>
|
||||
#include <byteswap.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "hwcrypto/sha.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "soc/dport_reg.h"
|
||||
@ -53,25 +55,30 @@ inline static uint32_t SHA_CONTINUE_REG(esp_sha_type sha_type) {
|
||||
return SHA_1_CONTINUE_REG + sha_type * 0x10;
|
||||
}
|
||||
|
||||
/* Single lock for SHA engine memory block
|
||||
/* Single spinlock for SHA engine memory block
|
||||
*/
|
||||
static _lock_t memory_block_lock;
|
||||
static portMUX_TYPE memory_block_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
typedef struct {
|
||||
_lock_t lock;
|
||||
bool in_use;
|
||||
} sha_engine_state;
|
||||
|
||||
/* Pointer to state of each concurrent SHA engine.
|
||||
/* Binary semaphore managing the state of each concurrent SHA engine.
|
||||
|
||||
Available = noone is using this SHA engine
|
||||
Taken = a SHA session is running on this SHA engine
|
||||
|
||||
Indexes:
|
||||
0 = SHA1
|
||||
1 = SHA2_256
|
||||
2 = SHA2_384 or SHA2_512
|
||||
*/
|
||||
static sha_engine_state engine_states[3];
|
||||
static SemaphoreHandle_t engine_states[3];
|
||||
|
||||
/* Index into the sha_engine_state array */
|
||||
static uint8_t engines_in_use;
|
||||
|
||||
/* Spinlock for engines_in_use counter
|
||||
*/
|
||||
static portMUX_TYPE engines_in_use_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
/* Index into the engine_states array */
|
||||
inline static size_t sha_engine_index(esp_sha_type type) {
|
||||
switch(type) {
|
||||
case SHA1:
|
||||
@ -115,82 +122,97 @@ inline static size_t block_length(esp_sha_type type) {
|
||||
|
||||
void esp_sha_lock_memory_block(void)
|
||||
{
|
||||
_lock_acquire(&memory_block_lock);
|
||||
portENTER_CRITICAL(&memory_block_lock);
|
||||
}
|
||||
|
||||
void esp_sha_unlock_memory_block(void)
|
||||
{
|
||||
_lock_release(&memory_block_lock);
|
||||
portEXIT_CRITICAL(&memory_block_lock);
|
||||
}
|
||||
|
||||
/* Lock to hold when changing SHA engine state,
|
||||
allows checking of sha_engines_all_idle()
|
||||
*/
|
||||
static _lock_t state_change_lock;
|
||||
static SemaphoreHandle_t sha_get_engine_state(esp_sha_type sha_type)
|
||||
{
|
||||
unsigned idx = sha_engine_index(sha_type);
|
||||
volatile SemaphoreHandle_t *engine = &engine_states[idx];
|
||||
SemaphoreHandle_t result = *engine;
|
||||
|
||||
inline static bool sha_engines_all_idle() {
|
||||
return !engine_states[0].in_use
|
||||
&& !engine_states[1].in_use
|
||||
&& !engine_states[2].in_use;
|
||||
if (result == NULL) {
|
||||
// Create a new semaphore for 'in use' flag
|
||||
SemaphoreHandle_t new_engine = xSemaphoreCreateBinary();
|
||||
assert(new_engine != NULL);
|
||||
xSemaphoreGive(new_engine); // start available
|
||||
|
||||
// try to atomically set the previously NULL *engine to new_engine
|
||||
uint32_t set_engine = (uint32_t)new_engine;
|
||||
uxPortCompareSet((volatile uint32_t *)engine, 0, &set_engine);
|
||||
|
||||
if (set_engine != 0) { // we lost a race setting *engine
|
||||
vSemaphoreDelete(new_engine);
|
||||
}
|
||||
result = *engine;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void esp_sha_lock_engine_inner(sha_engine_state *engine);
|
||||
static bool esp_sha_lock_engine_common(esp_sha_type sha_type, TickType_t ticks_to_wait);
|
||||
|
||||
bool esp_sha_try_lock_engine(esp_sha_type sha_type)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
if(_lock_try_acquire(&engine->lock) != 0) {
|
||||
/* This SHA engine is already in use */
|
||||
return false;
|
||||
} else {
|
||||
esp_sha_lock_engine_inner(engine);
|
||||
return true;
|
||||
}
|
||||
return esp_sha_lock_engine_common(sha_type, 0);
|
||||
}
|
||||
|
||||
void esp_sha_lock_engine(esp_sha_type sha_type)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
_lock_acquire(&engine->lock);
|
||||
esp_sha_lock_engine_inner(engine);
|
||||
esp_sha_lock_engine_common(sha_type, portMAX_DELAY);
|
||||
}
|
||||
|
||||
static void esp_sha_lock_engine_inner(sha_engine_state *engine)
|
||||
static bool esp_sha_lock_engine_common(esp_sha_type sha_type, TickType_t ticks_to_wait)
|
||||
{
|
||||
_lock_acquire(&state_change_lock);
|
||||
SemaphoreHandle_t engine_state = sha_get_engine_state(sha_type);
|
||||
BaseType_t result = xSemaphoreTake(engine_state, ticks_to_wait);
|
||||
|
||||
if (sha_engines_all_idle()) {
|
||||
/* Enable SHA hardware */
|
||||
if (result == pdFALSE) {
|
||||
// failed to take semaphore
|
||||
return false;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&engines_in_use_lock);
|
||||
|
||||
if (engines_in_use == 0) {
|
||||
/* Just locked first engine,
|
||||
so enable SHA hardware */
|
||||
periph_module_enable(PERIPH_SHA_MODULE);
|
||||
DPORT_STALL_OTHER_CPU_START();
|
||||
ets_sha_enable();
|
||||
DPORT_STALL_OTHER_CPU_END();
|
||||
}
|
||||
|
||||
assert( !engine->in_use && "in_use flag should be cleared" );
|
||||
engine->in_use = true;
|
||||
engines_in_use++;
|
||||
assert(engines_in_use <= 3);
|
||||
|
||||
_lock_release(&state_change_lock);
|
||||
portEXIT_CRITICAL(&engines_in_use_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void esp_sha_unlock_engine(esp_sha_type sha_type)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
SemaphoreHandle_t *engine_state = sha_get_engine_state(sha_type);
|
||||
|
||||
_lock_acquire(&state_change_lock);
|
||||
portENTER_CRITICAL(&engines_in_use_lock);
|
||||
|
||||
assert( engine->in_use && "in_use flag should be set" );
|
||||
engine->in_use = false;
|
||||
engines_in_use--;
|
||||
|
||||
if (sha_engines_all_idle()) {
|
||||
/* Disable SHA hardware */
|
||||
if (engines_in_use == 0) {
|
||||
/* About to release last engine, so
|
||||
disable SHA hardware */
|
||||
periph_module_disable(PERIPH_SHA_MODULE);
|
||||
}
|
||||
|
||||
_lock_release(&state_change_lock);
|
||||
portEXIT_CRITICAL(&engines_in_use_lock);
|
||||
|
||||
_lock_release(&engine->lock);
|
||||
xSemaphoreGive(engine_state);
|
||||
}
|
||||
|
||||
void esp_sha_wait_idle(void)
|
||||
@ -207,8 +229,16 @@ void esp_sha_wait_idle(void)
|
||||
|
||||
void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
assert(engine->in_use && "SHA engine should be locked" );
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
SemaphoreHandle_t *engine_state = sha_get_engine_state(sha_type);
|
||||
assert(uxSemaphoreGetCount(engine_state) == 0 &&
|
||||
"SHA engine should be locked" );
|
||||
}
|
||||
#endif
|
||||
|
||||
// preemptively do this before entering the critical section, then re-check once in it
|
||||
esp_sha_wait_idle();
|
||||
|
||||
esp_sha_lock_memory_block();
|
||||
|
||||
@ -234,8 +264,16 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
|
||||
|
||||
void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
assert(engine->in_use && "SHA engine should be locked" );
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
SemaphoreHandle_t *engine_state = sha_get_engine_state(sha_type);
|
||||
assert(uxSemaphoreGetCount(engine_state) == 0 &&
|
||||
"SHA engine should be locked" );
|
||||
}
|
||||
#endif
|
||||
|
||||
// preemptively do this before entering the critical section, then re-check once in it
|
||||
esp_sha_wait_idle();
|
||||
|
||||
esp_sha_lock_memory_block();
|
||||
|
||||
|
@ -185,6 +185,13 @@ typedef enum {
|
||||
Fixed Root Setting of each device is variable as that setting changes of the root. */
|
||||
MESH_EVENT_SCAN_DONE, /**< if self-organized networking is disabled, user can call esp_wifi_scan_start() to trigger
|
||||
this event, and add the corresponding scan done handler in this event. */
|
||||
MESH_EVENT_NETWORK_STATE, /**< network state, such as whether current mesh network has a root. */
|
||||
MESH_EVENT_STOP_RECONNECTION, /**< the root stops reconnecting to the router and non-root devices stop reconnecting to their parents. */
|
||||
MESH_EVENT_FIND_NETWORK, /**< when the channel field in mesh configuration is set to zero, mesh stack will perform a
|
||||
full channel scan to find a mesh network that can join, and return the channel value
|
||||
after finding it. */
|
||||
MESH_EVENT_ROUTER_SWITCH, /**< if users specify BSSID of the router in mesh configuration, when the root connects to another
|
||||
router with the same SSID, this event will be posted and the new router information is attached. */
|
||||
MESH_EVENT_MAX,
|
||||
} mesh_event_id_t;
|
||||
|
||||
@ -229,13 +236,18 @@ typedef enum {
|
||||
* @brief Mesh disconnect reason code
|
||||
*/
|
||||
typedef enum {
|
||||
MESH_REASON_CYCLIC = 100, /**< cyclic is detected */
|
||||
MESH_REASON_PARENT_IDLE, /**< parent is idle */
|
||||
MESH_REASON_LEAF, /**< the connected device is changed to a leaf */
|
||||
MESH_REASON_DIFF_ID, /**< in different mesh ID */
|
||||
MESH_REASON_ROOTS, /**< root conflict is detected */
|
||||
MESH_REASON_PARENT_STOPPED, /**< parent has stopped the mesh */
|
||||
MESH_REASON_SCAN_FAIL, /**< scan fail */
|
||||
MESH_REASON_CYCLIC = 100, /**< cyclic is detected */
|
||||
MESH_REASON_PARENT_IDLE, /**< parent is idle */
|
||||
MESH_REASON_LEAF, /**< the connected device is changed to a leaf */
|
||||
MESH_REASON_DIFF_ID, /**< in different mesh ID */
|
||||
MESH_REASON_ROOTS, /**< root conflict is detected */
|
||||
MESH_REASON_PARENT_STOPPED, /**< parent has stopped the mesh */
|
||||
MESH_REASON_SCAN_FAIL, /**< scan fail */
|
||||
MESH_REASON_IE_UNKNOWN, /**< unknown IE */
|
||||
MESH_REASON_WAIVE_ROOT, /**< waive root */
|
||||
MESH_REASON_PARENT_WORSE, /**< parent with very poor RSSI */
|
||||
MESH_REASON_EMPTY_PASSWORD, /**< use an empty password to connect to an encrypted parent */
|
||||
MESH_REASON_PARENT_UNENCRYPTED, /**< connect to an unencrypted parent/router */
|
||||
} mesh_disconnect_reason_t;
|
||||
|
||||
/*******************************************************
|
||||
@ -303,6 +315,14 @@ typedef struct {
|
||||
mesh_addr_t rc_addr; /**< root address specified by users via API esp_mesh_waive_root() */
|
||||
} mesh_event_vote_started_t;
|
||||
|
||||
/**
|
||||
* @brief find a mesh network that this device can join
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t channel; /**< channel number of the new found network */
|
||||
uint8_t router_bssid[6]; /**< router BSSID */
|
||||
} mesh_event_find_network_t;
|
||||
|
||||
/**
|
||||
* @brief IP settings from LwIP stack
|
||||
*/
|
||||
@ -367,6 +387,18 @@ typedef struct {
|
||||
uint8_t number; /**< the number of APs scanned */
|
||||
} mesh_event_scan_done_t;
|
||||
|
||||
/**
|
||||
* @brief Network state information
|
||||
*/
|
||||
typedef struct {
|
||||
bool is_rootless; /**< whether current mesh network has a root */
|
||||
} mesh_event_network_state_t;
|
||||
|
||||
/**
|
||||
* @brief New router information
|
||||
*/
|
||||
typedef system_event_sta_connected_t mesh_event_router_switch_t;
|
||||
|
||||
/**
|
||||
* @brief Mesh event information
|
||||
*/
|
||||
@ -390,6 +422,9 @@ typedef union {
|
||||
mesh_event_root_conflict_t root_conflict; /**< other powerful root */
|
||||
mesh_event_root_fixed_t root_fixed; /**< fixed root */
|
||||
mesh_event_scan_done_t scan_done; /**< scan done */
|
||||
mesh_event_network_state_t network_state; /**< network state, such as whether current mesh network has a root. */
|
||||
mesh_event_find_network_t find_network; /**< network found that can join */
|
||||
mesh_event_router_switch_t router_switch; /**< new router information */
|
||||
} mesh_event_info_t;
|
||||
|
||||
/**
|
||||
@ -430,10 +465,16 @@ typedef struct {
|
||||
* @brief Router configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ssid[32]; /**< SSID */
|
||||
uint8_t ssid_len; /**< length of SSID */
|
||||
uint8_t bssid[6]; /**< BSSID, if router is hidden, this value is mandatory */
|
||||
uint8_t password[64]; /**< password */
|
||||
uint8_t ssid[32]; /**< SSID */
|
||||
uint8_t ssid_len; /**< length of SSID */
|
||||
uint8_t bssid[6]; /**< BSSID, if this value is specified, users should also specify "allow_router_switch". */
|
||||
uint8_t password[64]; /**< password */
|
||||
bool allow_router_switch; /**< if the BSSID is specified and this value is also set, when the router of this specified BSSID
|
||||
fails to be found after "fail" (mesh_attempts_t) times, the whole network is allowed to switch
|
||||
to another router with the same SSID. The new router might also be on a different channel.
|
||||
The default value is false.
|
||||
There is a risk that if the password is different between the new switched router and the previous
|
||||
one, the mesh network could be established but the root will never connect to the new switched router. */
|
||||
} mesh_router_t;
|
||||
|
||||
/**
|
||||
@ -449,6 +490,8 @@ typedef struct {
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t channel; /**< channel, the mesh network on */
|
||||
bool allow_channel_switch; /**< if this value is set, when "fail" (mesh_attempts_t) times is reached, device will change to
|
||||
a full channel scan for a network that could join. The default value is false. */
|
||||
mesh_event_cb_t event_cb; /**< mesh event callback */
|
||||
mesh_addr_t mesh_id; /**< mesh network identification */
|
||||
mesh_router_t router; /**< router configuration */
|
||||
@ -581,6 +624,7 @@ esp_err_t esp_mesh_stop(void);
|
||||
* - If the packet is to an external IP network, set this parameter to the IPv4:PORT combination.
|
||||
* This packet will be delivered to the root firstly, then the root will forward this packet to the final IP server address.
|
||||
* @param[in] data pointer to a sending mesh packet
|
||||
* - Field size should not exceed MESH_MPS. Note that the size of one mesh packet should not exceed MESH_MTU.
|
||||
* - Field proto should be set to data protocol in use (default is MESH_PROTO_BIN for binary).
|
||||
* - Field tos should be set to transmission tos (type of service) in use (default is MESH_TOS_P2P for point-to-point reliable).
|
||||
* @param[in] flag bitmap for data sent
|
||||
@ -927,9 +971,9 @@ bool esp_mesh_is_root(void);
|
||||
* @attention This API is used to dynamically modify whether to enable the self organizing.
|
||||
*
|
||||
* @param[in] enable enable or disable self-organized networking
|
||||
* @param[in] select_parent
|
||||
* - If self-organized networking is enabled, let the device search for a new parent or
|
||||
* keep connecting to the previous parent.
|
||||
* @param[in] select_parent Only valid when self-organized networking is enabled.
|
||||
* - if select_parent is set to true, the root will give up its mesh root status and search for a new parent
|
||||
* like other non-root devices.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
@ -1000,9 +1044,10 @@ esp_err_t esp_mesh_set_vote_percentage(float percentage);
|
||||
float esp_mesh_get_vote_percentage(void);
|
||||
|
||||
/**
|
||||
* @brief Set mesh softAP associate expired time
|
||||
* @brief Set mesh softAP associate expired time (default:10 seconds)
|
||||
* - If mesh softAP hasn't received any data from an associated child within this time,
|
||||
* mesh softAP will take this child inactive and disassociate it.
|
||||
* - If mesh softAP is encrypted, this value should be set a greater value, such as 30 seconds.
|
||||
*
|
||||
* @param[in] seconds the expired time
|
||||
*
|
||||
@ -1183,7 +1228,7 @@ esp_err_t esp_mesh_get_group_list(mesh_addr_t *addr, int num);
|
||||
bool esp_mesh_is_my_group(const mesh_addr_t *addr);
|
||||
|
||||
/**
|
||||
* @brief Set mesh network capacity
|
||||
* @brief Set mesh network capacity (max:1000, default:300)
|
||||
*
|
||||
* @attention This API shall be called before mesh is started.
|
||||
*
|
||||
@ -1381,6 +1426,59 @@ esp_err_t esp_mesh_get_subnet_nodes_num(const mesh_addr_t *child_mac, int *nodes
|
||||
*/
|
||||
esp_err_t esp_mesh_get_subnet_nodes_list(const mesh_addr_t *child_mac, mesh_addr_t *nodes, int nodes_num);
|
||||
|
||||
/**
|
||||
* @brief Disconnect from current parent
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
*/
|
||||
esp_err_t esp_mesh_disconnect(void);
|
||||
|
||||
/**
|
||||
* @brief Connect to current parent
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
*/
|
||||
esp_err_t esp_mesh_connect(void);
|
||||
|
||||
/**
|
||||
* @brief Flush scan result
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
*/
|
||||
esp_err_t esp_mesh_flush_scan_result(void);
|
||||
|
||||
/**
|
||||
* @brief Cause the root device to add Channel Switch Announcement Element (CSA IE) to beacon
|
||||
* - Set the new channel
|
||||
* - Set how many beacons with CSA IE will be sent before changing a new channel
|
||||
* - Enable the channel switch function
|
||||
*
|
||||
* @attention This API is only called by the root.
|
||||
*
|
||||
* @param[in] new_bssid the new router BSSID if the router changes
|
||||
* @param[in] csa_newchan the new channel number to which the whole network is moving
|
||||
* @param[in] csa_count channel switch period(beacon count), unit is based on beacon interval of its softAP, the default value is 15.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
*/
|
||||
esp_err_t esp_mesh_switch_channel(const uint8_t *new_bssid, int csa_newchan, int csa_count);
|
||||
|
||||
/**
|
||||
* @brief Get the router BSSID
|
||||
*
|
||||
* @param[out] router_bssid pointer to the router BSSID
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_WIFI_NOT_INIT
|
||||
* - ESP_ERR_WIFI_ARG
|
||||
*/
|
||||
esp_err_t esp_mesh_get_router_bssid(uint8_t *router_bssid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -214,6 +214,12 @@ esp_err_t esp_modem_sleep_register(modem_sleep_module_t module);
|
||||
*/
|
||||
esp_err_t esp_modem_sleep_deregister(modem_sleep_module_t module);
|
||||
|
||||
/**
|
||||
* @brief Get the time stamp when PHY/RF was switched on
|
||||
* @return return 0 if PHY/RF is never switched on. Otherwise return time in
|
||||
* microsecond since boot when phy/rf was last switched on
|
||||
*/
|
||||
int64_t esp_phy_rf_get_on_ts(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -22,8 +22,9 @@
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef enum {
|
||||
ESP_SPIRAM_SIZE_32MBITS = 0, /*!< SPI RAM size is 32 MBits */
|
||||
ESP_SPIRAM_SIZE_64MBITS = 1, /*!< SPI RAM size is 64 MBits */
|
||||
ESP_SPIRAM_SIZE_16MBITS = 0, /*!< SPI RAM size is 16 MBits */
|
||||
ESP_SPIRAM_SIZE_32MBITS = 1, /*!< SPI RAM size is 32 MBits */
|
||||
ESP_SPIRAM_SIZE_64MBITS = 2, /*!< SPI RAM size is 64 MBits */
|
||||
ESP_SPIRAM_SIZE_INVALID, /*!< SPI RAM size is invalid */
|
||||
} esp_spiram_size_t;
|
||||
|
||||
@ -56,7 +57,7 @@ void esp_spiram_init_cache();
|
||||
|
||||
/**
|
||||
* @brief Memory test for SPI RAM. Should be called after SPI RAM is initialized and
|
||||
* (in case of a dual-core system) the app CPU is online. This test overwrites the
|
||||
* (in case of a dual-core system) the app CPU is online. This test overwrites the
|
||||
* memory with crap, so do not call after e.g. the heap allocator has stored important
|
||||
* stuff in SPI RAM.
|
||||
*
|
||||
@ -102,4 +103,14 @@ void esp_spiram_writeback_cache();
|
||||
esp_err_t esp_spiram_reserve_dma_pool(size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief If SPI RAM(PSRAM) has been initialized
|
||||
*
|
||||
* @return
|
||||
* - true SPI RAM has been initialized successfully
|
||||
* - false SPI RAM hasn't been initialized or initialized failed
|
||||
*/
|
||||
bool esp_spiram_is_initialized(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -405,7 +405,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
wifi_pkt_rx_ctrl_t rx_ctrl;/**< received packet radio metadata header of the CSI data */
|
||||
uint8_t mac[6]; /**< source MAC address of the CSI data */
|
||||
bool last_word_invalid; /**< last four bytes of the CSI data is invalid or not */
|
||||
bool first_word_invalid; /**< first four bytes of the CSI data is invalid or not */
|
||||
int8_t *buf; /**< buffer of CSI data */
|
||||
uint16_t len; /**< length of CSI data */
|
||||
} wifi_csi_info_t;
|
||||
|
@ -166,6 +166,8 @@ void esp_sha_unlock_engine(esp_sha_type sha_type);
|
||||
* while it is in use by the SHA engine. Caller should use esp_sha_wait_idle()
|
||||
* to ensure the SHA engine is not reading from the memory block in hardware.
|
||||
*
|
||||
* @note This function enters a critical section. Do not block while holding this lock.
|
||||
*
|
||||
* @note You do not need to lock the memory block before calling esp_sha_block() or esp_sha_read_digest_state(), these functions handle memory block locking internally.
|
||||
*
|
||||
* Call esp_sha_unlock_memory_block() when done.
|
||||
@ -177,6 +179,8 @@ void esp_sha_lock_memory_block(void);
|
||||
*
|
||||
* Caller should have already locked a SHA engine before calling this function.
|
||||
*
|
||||
* This function releases the critical section entered by esp_sha_lock_memory_block().
|
||||
*
|
||||
* Call following esp_sha_lock_memory_block().
|
||||
*/
|
||||
void esp_sha_unlock_memory_block(void);
|
||||
|
@ -1401,5 +1401,16 @@ extern const unsigned int XCJOIN(Xthal_cp_mask_,XCHAL_CP7_IDENT);
|
||||
#define XCHAL_ERRATUM_497 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Erratum 572 (releases TBD, but present in ESP32)
|
||||
* Disable zero-overhead loop buffer to prevent rare illegal instruction
|
||||
* exceptions while executing zero-overhead loops.
|
||||
*/
|
||||
#if ( XCHAL_HAVE_LOOPS && XCHAL_LOOP_BUFFER_SIZE != 0 )
|
||||
#define XCHAL_ERRATUM_572 1
|
||||
#else
|
||||
#define XCHAL_ERRATUM_572 0
|
||||
#endif
|
||||
|
||||
#endif /*XTENSA_CONFIG_CORE_H*/
|
||||
|
||||
|
@ -12,6 +12,7 @@ SECTIONS
|
||||
*libpp.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON)
|
||||
*liblwip.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON)
|
||||
*libbt.a:(EXCLUDE_FILE (libbtdm_app.a) .dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON)
|
||||
. = ALIGN(4);
|
||||
_ext_ram_bss_end = ABSOLUTE(.);
|
||||
} > extern_ram_seg
|
||||
}
|
||||
|
@ -88,6 +88,8 @@ PROVIDE ( esp_crc8 = 0x4005d144 );
|
||||
PROVIDE ( _etext = 0x4000d66c );
|
||||
PROVIDE ( ets_readySet_ = 0x3ffe01f0 );
|
||||
PROVIDE ( ets_startup_callback = 0x3ffe0404 );
|
||||
PROVIDE ( rwip_coex_cfg = 0x3ff9914c );
|
||||
PROVIDE ( rwip_priority = 0x3ff99159 );
|
||||
PROVIDE ( exc_cause_table = 0x3ff991d0 );
|
||||
PROVIDE ( _exit_r = 0x4000bd28 );
|
||||
PROVIDE ( free = 0x4000beb8 );
|
||||
@ -675,6 +677,9 @@ PROVIDE ( ld_sco_modify = 0x40031778 );
|
||||
PROVIDE ( lm_cmd_cmp_send = 0x40051838 );
|
||||
PROVIDE ( ld_sco_frm_cbk = 0x400349dc );
|
||||
PROVIDE ( ld_acl_sniff_frm_cbk = 0x4003482c );
|
||||
PROVIDE ( ld_inq_end = 0x4003ab48 );
|
||||
PROVIDE ( ld_inq_sched = 0x4003aba4 );
|
||||
PROVIDE ( ld_inq_frm_cbk = 0x4003ae4c );
|
||||
PROVIDE ( r_ld_acl_active_hop_types_get = 0x40036e10 );
|
||||
PROVIDE ( r_ld_acl_afh_confirm = 0x40036d40 );
|
||||
PROVIDE ( r_ld_acl_afh_prepare = 0x40036c84 );
|
||||
|
@ -8,136 +8,136 @@
|
||||
This file is responsible for placing the rodata segment in DRAM.
|
||||
*/
|
||||
|
||||
*lib_a-utoa.o(.rodata .rodata.*)
|
||||
*lib_a-longjmp.o(.rodata .rodata.*)
|
||||
*lib_a-setjmp.o(.rodata .rodata.*)
|
||||
*lib_a-abs.o(.rodata .rodata.*)
|
||||
*lib_a-div.o(.rodata .rodata.*)
|
||||
*lib_a-labs.o(.rodata .rodata.*)
|
||||
*lib_a-ldiv.o(.rodata .rodata.*)
|
||||
*lib_a-quorem.o(.rodata .rodata.*)
|
||||
*lib_a-qsort.o(.rodata .rodata.*)
|
||||
*lib_a-utoa.o(.rodata .rodata.*)
|
||||
*lib_a-itoa.o(.rodata .rodata.*)
|
||||
*lib_a-atoi.o(.rodata .rodata.*)
|
||||
*lib_a-atol.o(.rodata .rodata.*)
|
||||
*lib_a-strtol.o(.rodata .rodata.*)
|
||||
*lib_a-strtoul.o(.rodata .rodata.*)
|
||||
*lib_a-wcrtomb.o(.rodata .rodata.*)
|
||||
*lib_a-fvwrite.o(.rodata .rodata.*)
|
||||
*lib_a-wbuf.o(.rodata .rodata.*)
|
||||
*lib_a-wsetup.o(.rodata .rodata.*)
|
||||
*lib_a-fputwc.o(.rodata .rodata.*)
|
||||
*lib_a-wctomb_r.o(.rodata .rodata.*)
|
||||
*lib_a-ungetc.o(.rodata .rodata.*)
|
||||
*lib_a-makebuf.o(.rodata .rodata.*)
|
||||
*lib_a-fflush.o(.rodata .rodata.*)
|
||||
*lib_a-refill.o(.rodata .rodata.*)
|
||||
*lib_a-s_fpclassify.o(.rodata .rodata.*)
|
||||
*lib_a-locale.o(.rodata .rodata.*)
|
||||
*lib_a-asctime.o(.rodata .rodata.*)
|
||||
*lib_a-ctime.o(.rodata .rodata.*)
|
||||
*lib_a-ctime_r.o(.rodata .rodata.*)
|
||||
*lib_a-lcltime.o(.rodata .rodata.*)
|
||||
*lib_a-lcltime_r.o(.rodata .rodata.*)
|
||||
*lib_a-gmtime.o(.rodata .rodata.*)
|
||||
*lib_a-gmtime_r.o(.rodata .rodata.*)
|
||||
*lib_a-strftime.o(.rodata .rodata.*)
|
||||
*lib_a-mktime.o(.rodata .rodata.*)
|
||||
*lib_a-syswrite.o(.rodata .rodata.*)
|
||||
*lib_a-tzset_r.o(.rodata .rodata.*)
|
||||
*lib_a-tzset.o(.rodata .rodata.*)
|
||||
*lib_a-toupper.o(.rodata .rodata.*)
|
||||
*lib_a-tolower.o(.rodata .rodata.*)
|
||||
*lib_a-toascii.o(.rodata .rodata.*)
|
||||
*lib_a-systimes.o(.rodata .rodata.*)
|
||||
*lib_a-time.o(.rodata .rodata.*)
|
||||
*lib_a-bsd_qsort_r.o(.rodata .rodata.*)
|
||||
*lib_a-qsort_r.o(.rodata .rodata.*)
|
||||
*lib_a-gettzinfo.o(.rodata .rodata.*)
|
||||
*lib_a-strupr.o(.rodata .rodata.*)
|
||||
*lib_a-asctime_r.o(.rodata .rodata.*)
|
||||
*lib_a-bzero.o(.rodata .rodata.*)
|
||||
*lib_a-close.o(.rodata .rodata.*)
|
||||
*lib_a-creat.o(.rodata .rodata.*)
|
||||
*lib_a-environ.o(.rodata .rodata.*)
|
||||
*lib_a-fclose.o(.rodata .rodata.*)
|
||||
*lib_a-isalnum.o(.rodata .rodata.*)
|
||||
*lib_a-isalpha.o(.rodata .rodata.*)
|
||||
*lib_a-isascii.o(.rodata .rodata.*)
|
||||
*lib_a-isblank.o(.rodata .rodata.*)
|
||||
*lib_a-iscntrl.o(.rodata .rodata.*)
|
||||
*lib_a-isdigit.o(.rodata .rodata.*)
|
||||
*lib_a-isgraph.o(.rodata .rodata.*)
|
||||
*lib_a-islower.o(.rodata .rodata.*)
|
||||
*lib_a-isprint.o(.rodata .rodata.*)
|
||||
*lib_a-ispunct.o(.rodata .rodata.*)
|
||||
*lib_a-isspace.o(.rodata .rodata.*)
|
||||
*lib_a-isupper.o(.rodata .rodata.*)
|
||||
*lib_a-memccpy.o(.rodata .rodata.*)
|
||||
*lib_a-memchr.o(.rodata .rodata.*)
|
||||
*lib_a-memcmp.o(.rodata .rodata.*)
|
||||
*lib_a-memcpy.o(.rodata .rodata.*)
|
||||
*lib_a-memmove.o(.rodata .rodata.*)
|
||||
*lib_a-memrchr.o(.rodata .rodata.*)
|
||||
*lib_a-memset.o(.rodata .rodata.*)
|
||||
*lib_a-open.o(.rodata .rodata.*)
|
||||
*lib_a-rand.o(.rodata .rodata.*)
|
||||
*lib_a-rand_r.o(.rodata .rodata.*)
|
||||
*lib_a-read.o(.rodata .rodata.*)
|
||||
*lib_a-rshift.o(.rodata .rodata.*)
|
||||
*lib_a-sbrk.o(.rodata .rodata.*)
|
||||
*lib_a-srand.o(.rodata .rodata.*)
|
||||
*lib_a-strcasecmp.o(.rodata .rodata.*)
|
||||
*lib_a-strcasestr.o(.rodata .rodata.*)
|
||||
*lib_a-strcat.o(.rodata .rodata.*)
|
||||
*lib_a-strchr.o(.rodata .rodata.*)
|
||||
*lib_a-strcmp.o(.rodata .rodata.*)
|
||||
*lib_a-strcoll.o(.rodata .rodata.*)
|
||||
*lib_a-strcpy.o(.rodata .rodata.*)
|
||||
*lib_a-strcspn.o(.rodata .rodata.*)
|
||||
*lib_a-strdup.o(.rodata .rodata.*)
|
||||
*lib_a-strlcat.o(.rodata .rodata.*)
|
||||
*lib_a-strlcpy.o(.rodata .rodata.*)
|
||||
*lib_a-strlen.o(.rodata .rodata.*)
|
||||
*lib_a-strlwr.o(.rodata .rodata.*)
|
||||
*lib_a-strncasecmp.o(.rodata .rodata.*)
|
||||
*lib_a-strncat.o(.rodata .rodata.*)
|
||||
*lib_a-strncmp.o(.rodata .rodata.*)
|
||||
*lib_a-strncpy.o(.rodata .rodata.*)
|
||||
*lib_a-strndup.o(.rodata .rodata.*)
|
||||
*lib_a-strnlen.o(.rodata .rodata.*)
|
||||
*lib_a-strrchr.o(.rodata .rodata.*)
|
||||
*lib_a-strsep.o(.rodata .rodata.*)
|
||||
*lib_a-strspn.o(.rodata .rodata.*)
|
||||
*lib_a-strstr.o(.rodata .rodata.*)
|
||||
*lib_a-strtok_r.o(.rodata .rodata.*)
|
||||
*lib_a-strupr.o(.rodata .rodata.*)
|
||||
*lib_a-stdio.o(.rodata .rodata.*)
|
||||
*lib_a-syssbrk.o(.rodata .rodata.*)
|
||||
*lib_a-sysclose.o(.rodata .rodata.*)
|
||||
*lib_a-sysopen.o(.rodata .rodata.*)
|
||||
*creat.o(.rodata .rodata.*)
|
||||
*lib_a-sysread.o(.rodata .rodata.*)
|
||||
*lib_a-syswrite.o(.rodata .rodata.*)
|
||||
*lib_a-impure.o(.rodata .rodata.*)
|
||||
*lib_a-tzvars.o(.rodata .rodata.*)
|
||||
*lib_a-sf_nan.o(.rodata .rodata.*)
|
||||
*lib_a-tzcalc_limits.o(.rodata .rodata.*)
|
||||
*lib_a-month_lengths.o(.rodata .rodata.*)
|
||||
*lib_a-timelocal.o(.rodata .rodata.*)
|
||||
*lib_a-findfp.o(.rodata .rodata.*)
|
||||
*lock.o(.rodata .rodata.*)
|
||||
*lib_a-getenv_r.o(.rodata .rodata.*)
|
||||
*isatty.o(.rodata .rodata.*)
|
||||
*lib_a-fwalk.o(.rodata .rodata.*)
|
||||
*lib_a-getenv_r.o(.rodata .rodata.*)
|
||||
*lib_a-tzlock.o(.rodata .rodata.*)
|
||||
*lib_a-ctype_.o(.rodata .rodata.*)
|
||||
*lib_a-sccl.o(.rodata .rodata.*)
|
||||
*lib_a-strptime.o(.rodata .rodata.*)
|
||||
*lib_a-envlock.o(.rodata .rodata.*)
|
||||
*lib_a-raise.o(.rodata .rodata.*)
|
||||
*lib_a-strdup_r.o(.rodata .rodata.*)
|
||||
*lib_a-system.o(.rodata .rodata.*)
|
||||
*lib_a-strndup_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-utoa.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-longjmp.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-setjmp.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-abs.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-div.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-labs.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-ldiv.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-quorem.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-qsort.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-utoa.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-itoa.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-atoi.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-atol.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strtol.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strtoul.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-wcrtomb.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-fvwrite.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-wbuf.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-wsetup.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-fputwc.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-wctomb_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-ungetc.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-makebuf.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-fflush.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-refill.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-s_fpclassify.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-locale.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-asctime.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-ctime.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-ctime_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-lcltime.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-lcltime_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-gmtime.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-gmtime_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strftime.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-mktime.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-syswrite.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzset_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzset.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-toupper.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-tolower.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-toascii.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-systimes.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-time.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-bsd_qsort_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-qsort_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-gettzinfo.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strupr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-asctime_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-bzero.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-close.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-creat.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-environ.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-fclose.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isalnum.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isalpha.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isascii.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isblank.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-iscntrl.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isdigit.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isgraph.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-islower.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isprint.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-ispunct.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isspace.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-isupper.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-memccpy.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-memchr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-memcmp.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-memcpy.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-memmove.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-memrchr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-memset.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-open.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-rand.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-rand_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-read.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-rshift.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-sbrk.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-srand.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcasecmp.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcasestr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcat.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strchr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcmp.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcoll.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcpy.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcspn.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strdup.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strlcat.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strlcpy.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strlen.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strlwr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strncasecmp.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strncat.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strncmp.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strncpy.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strndup.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strnlen.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strrchr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strsep.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strspn.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strstr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strtok_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strupr.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-stdio.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-syssbrk.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-sysclose.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-sysopen.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*creat.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-sysread.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-syswrite.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-impure.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzvars.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-sf_nan.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzcalc_limits.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-month_lengths.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-timelocal.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-findfp.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lock.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-getenv_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*isatty.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-fwalk.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-getenv_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzlock.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-ctype_.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-sccl.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strptime.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-envlock.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-raise.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strdup_r.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-system.o(.rodata .rodata.*)
|
||||
*libc-psram-workaround.a:*lib_a-strndup_r.o(.rodata .rodata.*)
|
||||
|
@ -9,136 +9,132 @@
|
||||
*/
|
||||
|
||||
|
||||
*lib_a-utoa.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-longjmp.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-setjmp.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-abs.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-div.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-labs.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-ldiv.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-quorem.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-qsort.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-utoa.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-itoa.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-atoi.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-atol.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strtol.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strtoul.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-wcrtomb.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-fvwrite.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-wbuf.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-wsetup.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-fputwc.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-wctomb_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-ungetc.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-makebuf.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-fflush.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-refill.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-s_fpclassify.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-locale.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-asctime.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-ctime.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-ctime_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-lcltime.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-lcltime_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-gmtime.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-gmtime_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strftime.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-mktime.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-syswrite.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-tzset_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-tzset.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-toupper.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-tolower.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-toascii.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-systimes.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-time.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-bsd_qsort_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-qsort_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-gettzinfo.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strupr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-asctime_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-bzero.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-close.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-creat.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-environ.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-fclose.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isalnum.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isalpha.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isascii.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isblank.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-iscntrl.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isdigit.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isgraph.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-islower.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isprint.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-ispunct.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isspace.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-isupper.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-memccpy.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-memchr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-memcmp.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-memcpy.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-memmove.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-memrchr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-memset.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-open.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-rand.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-rand_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-read.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-rshift.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-sbrk.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-srand.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strcasecmp.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strcasestr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strcat.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strchr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strcmp.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strcoll.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strcpy.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strcspn.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strdup.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strlcat.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strlcpy.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strlen.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strlwr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strncasecmp.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strncat.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strncmp.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strncpy.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strndup.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strnlen.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strrchr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strsep.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strspn.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strstr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strtok_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strupr.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-stdio.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-syssbrk.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-sysclose.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-sysopen.o(.literal .text .literal.* .text.*)
|
||||
*creat.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-sysread.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-syswrite.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-impure.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-tzvars.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-sf_nan.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-tzcalc_limits.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-month_lengths.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-timelocal.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-findfp.o(.literal .text .literal.* .text.*)
|
||||
*lock.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-getenv_r.o(.literal .text .literal.* .text.*)
|
||||
*isatty.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-fwalk.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-getenv_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-tzlock.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-ctype_.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-sccl.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strptime.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-envlock.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-raise.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strdup_r.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-system.o(.literal .text .literal.* .text.*)
|
||||
*lib_a-strndup_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-utoa.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-longjmp.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-setjmp.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-abs.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-div.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-labs.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-ldiv.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-quorem.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-utoa.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-itoa.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-atoi.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-atol.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strtol.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strtoul.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-wcrtomb.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-fvwrite.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-wbuf.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-wsetup.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-fputwc.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-wctomb_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-ungetc.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-makebuf.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-fflush.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-refill.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-s_fpclassify.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-asctime.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-ctime.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-ctime_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-lcltime.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-lcltime_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-gmtime.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-gmtime_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strftime.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-mktime.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-syswrite.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzset_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzset.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-toupper.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-tolower.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-toascii.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-systimes.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-time.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-gettzinfo.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strupr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-asctime_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-bzero.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-close.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-creat.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-environ.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-fclose.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isalnum.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isalpha.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isascii.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isblank.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-iscntrl.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isdigit.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isgraph.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-islower.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isprint.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-ispunct.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isspace.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-isupper.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-memccpy.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-memchr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-memcmp.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-memcpy.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-memmove.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-memrchr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-memset.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-open.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-rand.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-rand_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-read.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-rshift.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-sbrk.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-srand.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcasecmp.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcasestr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcat.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strchr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcmp.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcoll.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcpy.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strcspn.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strdup.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strlcat.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strlcpy.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strlen.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strlwr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strncasecmp.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strncat.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strncmp.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strncpy.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strndup.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strnlen.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strrchr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strsep.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strspn.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strstr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strtok_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strupr.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-stdio.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-syssbrk.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-sysclose.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-sysopen.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*creat.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-sysread.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-syswrite.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-impure.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzvars.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-sf_nan.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzcalc_limits.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-month_lengths.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-timelocal.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-findfp.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lock.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-getenv_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*isatty.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-fwalk.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-getenv_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-tzlock.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-ctype_.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-sccl.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strptime.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-envlock.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-raise.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strdup_r.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-system.o(.literal .text .literal.* .text.*)
|
||||
*libc-psram-workaround.a:*lib_a-strndup_r.o(.literal .text .literal.* .text.*)
|
||||
|
Submodule components/esp32/lib updated: ee0d0b152f...eb53491cf6
@ -188,6 +188,7 @@ static const char *edesc[] = {
|
||||
|
||||
static void commonErrorHandler(XtExcFrame *frame);
|
||||
static inline void disableAllWdts();
|
||||
static void illegal_instruction_helper(XtExcFrame *frame);
|
||||
|
||||
//The fact that we've panic'ed probably means the other CPU is now running wild, possibly
|
||||
//messing up the serial output, so we stall it here.
|
||||
@ -357,11 +358,37 @@ void xt_unhandled_exception(XtExcFrame *frame)
|
||||
return;
|
||||
}
|
||||
panicPutStr(". Exception was unhandled.\r\n");
|
||||
if (exccause == 0 /* IllegalInstruction */) {
|
||||
illegal_instruction_helper(frame);
|
||||
}
|
||||
esp_reset_reason_set_hint(ESP_RST_PANIC);
|
||||
}
|
||||
commonErrorHandler(frame);
|
||||
}
|
||||
|
||||
static void illegal_instruction_helper(XtExcFrame *frame)
|
||||
{
|
||||
/* Print out memory around the instruction word */
|
||||
uint32_t epc = frame->pc;
|
||||
epc = (epc & ~0x3) - 4;
|
||||
|
||||
/* check that the address was sane */
|
||||
if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) {
|
||||
return;
|
||||
}
|
||||
volatile uint32_t* pepc = (uint32_t*)epc;
|
||||
|
||||
panicPutStr("Memory dump at 0x");
|
||||
panicPutHex(epc);
|
||||
panicPutStr(": ");
|
||||
|
||||
panicPutHex(*pepc);
|
||||
panicPutStr(" ");
|
||||
panicPutHex(*(pepc + 1));
|
||||
panicPutStr(" ");
|
||||
panicPutHex(*(pepc + 2));
|
||||
panicPutStr("\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
|
||||
|
@ -48,7 +48,7 @@ static _lock_t s_phy_rf_init_lock;
|
||||
/* Bit mask of modules needing to call phy_rf_init */
|
||||
static uint32_t s_module_phy_rf_init = 0;
|
||||
|
||||
/* Whether modern sleep in turned on */
|
||||
/* Whether modem sleep is turned on */
|
||||
static volatile bool s_is_phy_rf_en = false;
|
||||
|
||||
/* Bit mask of modules needing to enter modem sleep mode */
|
||||
@ -64,6 +64,9 @@ static volatile bool s_is_modem_sleep_en = false;
|
||||
|
||||
static _lock_t s_modem_sleep_lock;
|
||||
|
||||
/* time stamp updated when the PHY/RF is turned on */
|
||||
static int64_t s_phy_rf_en_ts = 0;
|
||||
|
||||
uint32_t IRAM_ATTR phy_enter_critical(void)
|
||||
{
|
||||
return portENTER_CRITICAL_NESTED();
|
||||
@ -74,16 +77,20 @@ void IRAM_ATTR phy_exit_critical(uint32_t level)
|
||||
portEXIT_CRITICAL_NESTED(level);
|
||||
}
|
||||
|
||||
static inline void phy_update_wifi_mac_time(bool en_clock_stopped)
|
||||
int64_t esp_phy_rf_get_on_ts(void)
|
||||
{
|
||||
return s_phy_rf_en_ts;
|
||||
}
|
||||
|
||||
static inline void phy_update_wifi_mac_time(bool en_clock_stopped, int64_t now)
|
||||
{
|
||||
static uint32_t s_common_clock_disable_time = 0;
|
||||
|
||||
if (en_clock_stopped) {
|
||||
s_common_clock_disable_time = esp_timer_get_time();
|
||||
s_common_clock_disable_time = (uint32_t)now;
|
||||
} else {
|
||||
if (s_common_clock_disable_time) {
|
||||
uint64_t now = esp_timer_get_time();
|
||||
uint32_t diff = now - s_common_clock_disable_time;
|
||||
uint32_t diff = (uint64_t)now - s_common_clock_disable_time;
|
||||
|
||||
esp_wifi_internal_update_mac_time(diff);
|
||||
s_common_clock_disable_time = 0;
|
||||
@ -135,8 +142,10 @@ esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, esp_phy_calibrat
|
||||
}
|
||||
}
|
||||
if (s_is_phy_rf_en == true){
|
||||
// Update time stamp
|
||||
s_phy_rf_en_ts = esp_timer_get_time();
|
||||
// Update WiFi MAC time before WiFi/BT common clock is enabled
|
||||
phy_update_wifi_mac_time( false );
|
||||
phy_update_wifi_mac_time(false, s_phy_rf_en_ts);
|
||||
// Enable WiFi/BT common peripheral clock
|
||||
periph_module_enable(PERIPH_WIFI_BT_COMMON_MODULE);
|
||||
phy_set_wifi_mode_only(0);
|
||||
@ -229,7 +238,7 @@ esp_err_t esp_phy_rf_deinit(phy_rf_module_t module)
|
||||
// Disable PHY and RF.
|
||||
phy_close_rf();
|
||||
// Update WiFi MAC time before disalbe WiFi/BT common peripheral clock
|
||||
phy_update_wifi_mac_time(true);
|
||||
phy_update_wifi_mac_time(true, esp_timer_get_time());
|
||||
// Disable WiFi/BT common peripheral clock. Do not disable clock for hardware RNG
|
||||
periph_module_disable(PERIPH_WIFI_BT_COMMON_MODULE);
|
||||
}
|
||||
|
@ -81,11 +81,20 @@ static uint32_t s_ccount_div;
|
||||
static uint32_t s_ccount_mul;
|
||||
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
/* Indicates if light sleep entry was successful for given CPU.
|
||||
/* Indicates if light sleep entry was skipped in vApplicationSleep for given CPU.
|
||||
* This in turn gets used in IDLE hook to decide if `waiti` needs
|
||||
* to be invoked or not.
|
||||
*/
|
||||
static bool s_entered_light_sleep[portNUM_PROCESSORS];
|
||||
static bool s_skipped_light_sleep[portNUM_PROCESSORS];
|
||||
|
||||
#if portNUM_PROCESSORS == 2
|
||||
/* When light sleep is finished on one CPU, it is possible that the other CPU
|
||||
* will enter light sleep again very soon, before interrupts on the first CPU
|
||||
* get a chance to run. To avoid such situation, set a flag for the other CPU to
|
||||
* skip light sleep attempt.
|
||||
*/
|
||||
static bool s_skip_light_sleep[portNUM_PROCESSORS];
|
||||
#endif // portNUM_PROCESSORS == 2
|
||||
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
|
||||
/* Indicates to the ISR hook that CCOMPARE needs to be updated on the given CPU.
|
||||
@ -465,10 +474,14 @@ void esp_pm_impl_waiti()
|
||||
{
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
int core_id = xPortGetCoreID();
|
||||
if (!s_entered_light_sleep[core_id]) {
|
||||
if (s_skipped_light_sleep[core_id]) {
|
||||
asm("waiti 0");
|
||||
} else {
|
||||
s_entered_light_sleep[core_id] = false;
|
||||
/* Interrupt took the CPU out of waiti and s_rtos_lock_handle[core_id]
|
||||
* is now taken. However since we are back to idle task, we can release
|
||||
* the lock so that vApplicationSleep can attempt to enter light sleep.
|
||||
*/
|
||||
esp_pm_impl_idle_hook();
|
||||
s_skipped_light_sleep[core_id] = false;
|
||||
}
|
||||
#else
|
||||
asm("waiti 0");
|
||||
@ -477,10 +490,35 @@ void esp_pm_impl_waiti()
|
||||
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
|
||||
static inline bool IRAM_ATTR should_skip_light_sleep(int core_id)
|
||||
{
|
||||
#if portNUM_PROCESSORS == 2
|
||||
if (s_skip_light_sleep[core_id]) {
|
||||
s_skip_light_sleep[core_id] = false;
|
||||
s_skipped_light_sleep[core_id] = true;
|
||||
return true;
|
||||
}
|
||||
#endif // portNUM_PROCESSORS == 2
|
||||
if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching) {
|
||||
s_skipped_light_sleep[core_id] = true;
|
||||
} else {
|
||||
s_skipped_light_sleep[core_id] = false;
|
||||
}
|
||||
return s_skipped_light_sleep[core_id];
|
||||
}
|
||||
|
||||
static inline void IRAM_ATTR other_core_should_skip_light_sleep(int core_id)
|
||||
{
|
||||
#if portNUM_PROCESSORS == 2
|
||||
s_skip_light_sleep[!core_id] = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
|
||||
{
|
||||
portENTER_CRITICAL(&s_switch_lock);
|
||||
if (s_mode == PM_MODE_LIGHT_SLEEP && !s_is_switching) {
|
||||
int core_id = xPortGetCoreID();
|
||||
if (!should_skip_light_sleep(core_id)) {
|
||||
/* Calculate how much we can sleep */
|
||||
int64_t next_esp_timer_alarm = esp_timer_get_next_alarm();
|
||||
int64_t now = esp_timer_get_time();
|
||||
@ -494,7 +532,6 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
#endif
|
||||
/* Enter sleep */
|
||||
int core_id = xPortGetCoreID();
|
||||
ESP_PM_TRACE_ENTER(SLEEP, core_id);
|
||||
int64_t sleep_start = esp_timer_get_time();
|
||||
esp_light_sleep_start();
|
||||
@ -516,7 +553,7 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
|
||||
;
|
||||
}
|
||||
}
|
||||
s_entered_light_sleep[core_id] = true;
|
||||
other_core_should_skip_light_sleep(core_id);
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&s_switch_lock);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Abstraction layer for spi-ram. For now, it's no more than a stub for the spiram_psram functions, but if
|
||||
Abstraction layer for spi-ram. For now, it's no more than a stub for the spiram_psram functions, but if
|
||||
we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
|
||||
*/
|
||||
|
||||
@ -61,7 +61,7 @@ static const char* TAG = "spiram";
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
|
||||
extern int _ext_ram_bss_start, _ext_ram_bss_end;
|
||||
extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end;
|
||||
#endif
|
||||
static bool spiram_inited=false;
|
||||
|
||||
@ -131,6 +131,8 @@ esp_spiram_size_t esp_spiram_get_chip_size()
|
||||
}
|
||||
psram_size_t psram_size = psram_get_size();
|
||||
switch (psram_size) {
|
||||
case PSRAM_SIZE_16MBITS:
|
||||
return ESP_SPIRAM_SIZE_16MBITS;
|
||||
case PSRAM_SIZE_32MBITS:
|
||||
return ESP_SPIRAM_SIZE_32MBITS;
|
||||
case PSRAM_SIZE_64MBITS:
|
||||
@ -159,7 +161,7 @@ esp_err_t esp_spiram_init()
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device",
|
||||
ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device",
|
||||
(esp_spiram_get_size()*8)/(1024*1024));
|
||||
ESP_EARLY_LOGI(TAG, "SPI RAM mode: %s", PSRAM_SPEED == PSRAM_CACHE_F40M_S40M ? "flash 40m sram 40m" : \
|
||||
PSRAM_SPEED == PSRAM_CACHE_F80M_S40M ? "flash 80m sram 40m" : \
|
||||
@ -214,6 +216,7 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size) {
|
||||
size_t esp_spiram_get_size()
|
||||
{
|
||||
psram_size_t size=esp_spiram_get_chip_size();
|
||||
if (size==PSRAM_SIZE_16MBITS) return 2*1024*1024;
|
||||
if (size==PSRAM_SIZE_32MBITS) return 4*1024*1024;
|
||||
if (size==PSRAM_SIZE_64MBITS) return 8*1024*1024;
|
||||
return CONFIG_SPIRAM_SIZE;
|
||||
@ -225,7 +228,7 @@ size_t esp_spiram_get_size()
|
||||
Note that this routine assumes some unique mapping for the first 2 banks of the PSRAM memory range, as well as the
|
||||
2 banks after the 2 MiB mark.
|
||||
*/
|
||||
void IRAM_ATTR esp_spiram_writeback_cache()
|
||||
void IRAM_ATTR esp_spiram_writeback_cache()
|
||||
{
|
||||
int x;
|
||||
volatile int i=0;
|
||||
@ -234,7 +237,7 @@ void IRAM_ATTR esp_spiram_writeback_cache()
|
||||
|
||||
if (!spiram_inited) return;
|
||||
|
||||
//We need cache enabled for this to work. Re-enable it if needed; make sure we
|
||||
//We need cache enabled for this to work. Re-enable it if needed; make sure we
|
||||
//disable it again on exit as well.
|
||||
if (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) {
|
||||
cache_was_disabled|=(1<<0);
|
||||
@ -257,10 +260,10 @@ void IRAM_ATTR esp_spiram_writeback_cache()
|
||||
}
|
||||
#else
|
||||
/*
|
||||
Low/high psram cache mode uses one 32K cache for the lowest 2MiB of SPI flash and another 32K for the highest
|
||||
Low/high psram cache mode uses one 32KB cache for the lowest 2MiB of SPI flash and another 32K for the highest
|
||||
2MiB. Clear this by reading from both regions.
|
||||
Note: this assumes the amount of external RAM is >2M. If it is 2M or less, what this code does is undefined. If
|
||||
we ever support external RAM chips of 2M or smaller, this may need adjusting.
|
||||
Note: this assumes the amount of external RAM is >2MB. If it is 2MB or less, what this code does is undefined. If
|
||||
we ever support external RAM chips of 2MB or smaller, this may need adjusting.
|
||||
*/
|
||||
for (x=0; x<1024*64; x+=32) {
|
||||
i+=psram[x];
|
||||
@ -280,4 +283,15 @@ void IRAM_ATTR esp_spiram_writeback_cache()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If SPI RAM(PSRAM) has been initialized
|
||||
*
|
||||
* @return true SPI RAM has been initialized successfully
|
||||
* @return false SPI RAM hasn't been initialized or initialized failed
|
||||
*/
|
||||
bool esp_spiram_is_initialized()
|
||||
{
|
||||
return spiram_inited;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -65,38 +65,110 @@ typedef enum {
|
||||
#define PSRAM_ID_EID_M 0xff
|
||||
#define PSRAM_ID_EID_S 16
|
||||
|
||||
#define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
|
||||
#define PSRAM_EID(id) (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
|
||||
#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD)
|
||||
// Use the [7:5](bit7~bit5) of EID to distinguish the psram size:
|
||||
//
|
||||
// BIT7 | BIT6 | BIT5 | SIZE(MBIT)
|
||||
// -------------------------------------
|
||||
// 0 | 0 | 0 | 16
|
||||
// 0 | 0 | 1 | 32
|
||||
// 0 | 1 | 0 | 64
|
||||
#define PSRAM_EID_SIZE_M 0x07
|
||||
#define PSRAM_EID_SIZE_S 5
|
||||
|
||||
// PSRAM_EID = 0x26 or 0x4x ----> 64MBit psram
|
||||
// PSRAM_EID = 0x20 ------------> 32MBit psram
|
||||
#define PSRAM_IS_64MBIT(id) ((PSRAM_EID(id) == 0x26) || ((PSRAM_EID(id) & 0xf0) == 0x40))
|
||||
typedef enum {
|
||||
PSRAM_EID_SIZE_16MBITS = 0,
|
||||
PSRAM_EID_SIZE_32MBITS = 1,
|
||||
PSRAM_EID_SIZE_64MBITS = 2,
|
||||
} psram_eid_size_t;
|
||||
|
||||
#define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
|
||||
#define PSRAM_EID(id) (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
|
||||
#define PSRAM_SIZE_ID(id) ((PSRAM_EID(id) >> PSRAM_EID_SIZE_S) & PSRAM_EID_SIZE_M)
|
||||
#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD)
|
||||
|
||||
// For the old version 32Mbit psram, using the spicial driver */
|
||||
#define PSRAM_IS_32MBIT_VER0(id) (PSRAM_EID(id) == 0x20)
|
||||
#define PSRAM_IS_64MBIT_TRIAL(id) (PSRAM_EID(id) == 0x26)
|
||||
|
||||
// IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we
|
||||
// currently support are 1.8V parts.
|
||||
// IO-pins for PSRAM.
|
||||
// WARNING: PSRAM shares all but the CS and CLK pins with the flash, so these defines
|
||||
// hardcode the flash pins as well, making this code incompatible with either a setup
|
||||
// that has the flash on non-standard pins or ESP32s with built-in flash.
|
||||
#define FLASH_CLK_IO 6 //Psram clock is a delayed version of this in 40MHz mode
|
||||
#define FLASH_CS_IO 11
|
||||
#define PSRAM_CLK_IO 17
|
||||
#define PSRAM_CS_IO 16
|
||||
#define PSRAM_SPIQ_IO 7
|
||||
#define PSRAM_SPID_IO 8
|
||||
#define PSRAM_SPIWP_IO 10
|
||||
#define PSRAM_SPIHD_IO 9
|
||||
#define FLASH_CLK_IO 6
|
||||
#define FLASH_CS_IO 11
|
||||
#define FLASH_SPIQ_SD0_IO 7
|
||||
#define FLASH_SPID_SD1_IO 8
|
||||
#define FLASH_SPIWP_SD3_IO 10
|
||||
#define FLASH_SPIHD_SD2_IO 9
|
||||
|
||||
#define PSRAM_CLK_IO 17
|
||||
#define PSRAM_CS_IO 16
|
||||
#define PSRAM_SPIQ_SD0_IO 7
|
||||
#define PSRAM_SPID_SD1_IO 8
|
||||
#define PSRAM_SPIWP_SD3_IO 10
|
||||
#define PSRAM_SPIHD_SD2_IO 9
|
||||
|
||||
// IO-pins of ESP32-PICO-D4 for PSRAM. PSRAM share clock with flash.
|
||||
// The CS IO can be overwrite via menuconfig.
|
||||
#define PICO_FLASH_CLK_IO 6
|
||||
#define PICO_FLASH_CS_IO 16
|
||||
#define PICO_FLASH_SPIQ_SD0_IO 17
|
||||
#define PICO_FLASH_SPID_SD1_IO 8
|
||||
#define PICO_FLASH_SPIWP_SD3_IO 7
|
||||
#define PICO_FLASH_SPIHD_SD2_IO 11
|
||||
|
||||
#define PICO_PSRAM_CLK_IO 6
|
||||
#define PICO_PSRAM_CS_IO CONFIG_PICO_PSRAM_CS_IO
|
||||
#define PICO_PSRAM_SPIQ_SD0_IO 17
|
||||
#define PICO_PSRAM_SPID_SD1_IO 8
|
||||
#define PICO_PSRAM_SPIWP_SD3_IO 7
|
||||
#define PICO_PSRAM_SPIHD_SD2_IO 11
|
||||
|
||||
typedef struct {
|
||||
uint8_t flash_clk_io;
|
||||
uint8_t flash_cs_io;
|
||||
uint8_t flash_spiq_sd0_io;
|
||||
uint8_t flash_spid_sd1_io;
|
||||
uint8_t flash_spiwp_sd3_io;
|
||||
uint8_t flash_spihd_sd2_io;
|
||||
uint8_t psram_clk_io;
|
||||
uint8_t psram_cs_io;
|
||||
uint8_t psram_spiq_sd0_io;
|
||||
uint8_t psram_spid_sd1_io;
|
||||
uint8_t psram_spiwp_sd3_io;
|
||||
uint8_t psram_spihd_sd2_io;
|
||||
} psram_io_t;
|
||||
|
||||
#define PSRAM_INTERNAL_IO_28 28
|
||||
#define PSRAM_INTERNAL_IO_29 29
|
||||
#define PSRAM_IO_MATRIX_DUMMY_40M 1
|
||||
#define PSRAM_IO_MATRIX_DUMMY_80M 2
|
||||
|
||||
#define _SPI_CACHE_PORT 0
|
||||
#define _SPI_FLASH_PORT 1
|
||||
#define _SPI_80M_CLK_DIV 1
|
||||
#define _SPI_40M_CLK_DIV 2
|
||||
#define _SPI_CACHE_PORT 0
|
||||
#define _SPI_FLASH_PORT 1
|
||||
#define _SPI_80M_CLK_DIV 1
|
||||
#define _SPI_40M_CLK_DIV 2
|
||||
|
||||
//For 4MB PSRAM, we need one more SPI host, select which one to use by kconfig
|
||||
#ifdef CONFIG_SPIRAM_OCCUPY_HSPI_HOST
|
||||
#define PSRAM_SPI_MODULE PERIPH_HSPI_MODULE
|
||||
#define PSRAM_SPI_HOST HSPI_HOST
|
||||
#define PSRAM_CLK_SIGNAL HSPICLK_OUT_IDX
|
||||
#define PSRAM_SPI_NUM PSRAM_SPI_2
|
||||
#define PSRAM_SPICLKEN DPORT_SPI2_CLK_EN
|
||||
#elif defined CONFIG_SPIRAM_OCCUPY_VSPI_HOST
|
||||
#define PSRAM_SPI_MODULE PERIPH_VSPI_MODULE
|
||||
#define PSRAM_SPI_HOST VSPI_HOST
|
||||
#define PSRAM_CLK_SIGNAL VSPICLK_OUT_IDX
|
||||
#define PSRAM_SPI_NUM PSRAM_SPI_3
|
||||
#define PSRAM_SPICLKEN DPORT_SPI3_CLK_EN
|
||||
#else //set to SPI avoid HSPI and VSPI being used
|
||||
#define PSRAM_SPI_MODULE PERIPH_SPI_MODULE
|
||||
#define PSRAM_SPI_HOST SPI_HOST
|
||||
#define PSRAM_CLK_SIGNAL SPICLK_OUT_IDX
|
||||
#define PSRAM_SPI_NUM PSRAM_SPI_1
|
||||
#define PSRAM_SPICLKEN DPORT_SPI01_CLK_EN
|
||||
#endif
|
||||
|
||||
static const char* TAG = "psram";
|
||||
typedef enum {
|
||||
@ -223,8 +295,6 @@ static uint32_t backup_usr[3];
|
||||
static uint32_t backup_usr1[3];
|
||||
static uint32_t backup_usr2[3];
|
||||
|
||||
|
||||
|
||||
//setup spi command/addr/data/dummy in user mode
|
||||
static int psram_cmd_config(psram_spi_num_t spi_num, psram_cmd_t* pInData)
|
||||
{
|
||||
@ -444,7 +514,7 @@ void IRAM_ATTR psram_spi_init(psram_spi_num_t spi_num, psram_cache_mode_t mode)
|
||||
* Psram mode init will overwrite original flash speed mode, so that it is possible to change psram and flash speed after OTA.
|
||||
* Flash read mode(QIO/QOUT/DIO/DOUT) will not be changed in app bin. It is decided by bootloader, OTA can not change this mode.
|
||||
*/
|
||||
static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
|
||||
static void IRAM_ATTR psram_gpio_config(psram_io_t psram_io, psram_cache_mode_t mode)
|
||||
{
|
||||
int spi_cache_dummy = 0;
|
||||
uint32_t rd_mode_reg = READ_PERI_REG(SPI_CTRL_REG(0));
|
||||
@ -457,15 +527,15 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
|
||||
}
|
||||
// In bootloader, all the signals are already configured,
|
||||
// We keep the following code in case the bootloader is some older version.
|
||||
gpio_matrix_out(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(PSRAM_SPIQ_IO, SPIQ_IN_IDX, 0);
|
||||
gpio_matrix_out(PSRAM_SPID_IO, SPID_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(PSRAM_SPID_IO, SPID_IN_IDX, 0);
|
||||
gpio_matrix_out(PSRAM_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(PSRAM_SPIWP_IO, SPIWP_IN_IDX, 0);
|
||||
gpio_matrix_out(PSRAM_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(PSRAM_SPIHD_IO, SPIHD_IN_IDX, 0);
|
||||
gpio_matrix_out(psram_io.flash_cs_io, SPICS0_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(psram_io.psram_spiq_sd0_io, SPIQ_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(psram_io.psram_spiq_sd0_io, SPIQ_IN_IDX, 0);
|
||||
gpio_matrix_out(psram_io.psram_spid_sd1_io, SPID_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(psram_io.psram_spid_sd1_io, SPID_IN_IDX, 0);
|
||||
gpio_matrix_out(psram_io.psram_spiwp_sd3_io, SPIWP_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(psram_io.psram_spiwp_sd3_io, SPIWP_IN_IDX, 0);
|
||||
gpio_matrix_out(psram_io.psram_spihd_sd2_io, SPIHD_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(psram_io.psram_spihd_sd2_io, SPIHD_IN_IDX, 0);
|
||||
|
||||
switch (mode) {
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
@ -476,8 +546,8 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
|
||||
esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_CACHE_PORT);
|
||||
esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_FLASH_PORT);
|
||||
//set drive ability for clock
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV, 2, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_clk_io], FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.psram_clk_io], FUN_DRV, 2, FUN_DRV_S);
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
extra_dummy = PSRAM_IO_MATRIX_DUMMY_80M;
|
||||
@ -487,8 +557,8 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
|
||||
esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_CACHE_PORT);
|
||||
esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_FLASH_PORT);
|
||||
//set drive ability for clock
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_clk_io], FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.psram_clk_io], FUN_DRV, 3, FUN_DRV_S);
|
||||
break;
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
|
||||
@ -498,8 +568,8 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
|
||||
esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_CACHE_PORT);
|
||||
esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_FLASH_PORT);
|
||||
//set drive ability for clock
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 2, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV, 2, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_clk_io], FUN_DRV, 2, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.psram_clk_io], FUN_DRV, 2, FUN_DRV_S);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -507,21 +577,24 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_USR_DUMMY); // dummy en
|
||||
|
||||
//select pin function gpio
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.flash_spiq_sd0_io], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.flash_spid_sd1_io], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.flash_spihd_sd2_io], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.flash_spiwp_sd3_io], PIN_FUNC_GPIO);
|
||||
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.flash_cs_io], PIN_FUNC_GPIO);
|
||||
//flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.psram_clk_io], FUNC_SD_CLK_SPICLK);
|
||||
}
|
||||
|
||||
psram_size_t psram_get_size()
|
||||
{
|
||||
if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
|
||||
return PSRAM_SIZE_32MBITS;
|
||||
} else if (PSRAM_IS_64MBIT(s_psram_id)) {
|
||||
if ((PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_64MBITS) || PSRAM_IS_64MBIT_TRIAL(s_psram_id)) {
|
||||
return PSRAM_SIZE_64MBITS;
|
||||
} else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_32MBITS) {
|
||||
return PSRAM_SIZE_32MBITS;
|
||||
} else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_16MBITS) {
|
||||
return PSRAM_SIZE_16MBITS;
|
||||
} else {
|
||||
return PSRAM_SIZE_MAX;
|
||||
}
|
||||
@ -530,52 +603,80 @@ psram_size_t psram_get_size()
|
||||
//psram gpio init , different working frequency we have different solutions
|
||||
esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) //psram init
|
||||
{
|
||||
psram_io_t psram_io;
|
||||
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
|
||||
uint32_t pkg_ver = chip_ver & 0x7;
|
||||
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) {
|
||||
ESP_EARLY_LOGE(TAG, "ESP32D2WD do not support psram yet");
|
||||
return ESP_FAIL;
|
||||
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
|
||||
ESP_EARLY_LOGE(TAG, "ESP32PICOD2 do not support psram yet");
|
||||
return ESP_FAIL;
|
||||
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
|
||||
ESP_EARLY_LOGE(TAG, "ESP32PICOD4 do not support psram yet");
|
||||
return ESP_FAIL;
|
||||
} else if ((pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) || (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4)) {
|
||||
ESP_EARLY_LOGI(TAG, "This chip is ESP32-PICO");
|
||||
rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config();
|
||||
if (cfg.tieh != RTC_VDDSDIO_TIEH_3_3V) {
|
||||
ESP_EARLY_LOGE(TAG, "VDDSDIO is not 3.3V");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
psram_io.flash_clk_io = PICO_FLASH_CLK_IO;
|
||||
psram_io.flash_cs_io = PICO_FLASH_CS_IO;
|
||||
psram_io.flash_spiq_sd0_io = PICO_FLASH_SPIQ_SD0_IO;
|
||||
psram_io.flash_spid_sd1_io = PICO_FLASH_SPID_SD1_IO;
|
||||
psram_io.flash_spiwp_sd3_io = PICO_FLASH_SPIWP_SD3_IO;
|
||||
psram_io.flash_spihd_sd2_io = PICO_FLASH_SPIHD_SD2_IO;
|
||||
psram_io.psram_clk_io = PICO_PSRAM_CLK_IO;
|
||||
psram_io.psram_cs_io = PICO_PSRAM_CS_IO;
|
||||
psram_io.psram_spiq_sd0_io = PICO_PSRAM_SPIQ_SD0_IO;
|
||||
psram_io.psram_spid_sd1_io = PICO_PSRAM_SPID_SD1_IO;
|
||||
psram_io.psram_spiwp_sd3_io = PICO_PSRAM_SPIWP_SD3_IO;
|
||||
psram_io.psram_spihd_sd2_io = PICO_PSRAM_SPIHD_SD2_IO;
|
||||
|
||||
s_clk_mode = PSRAM_CLK_MODE_NORM;
|
||||
} else {
|
||||
psram_io.flash_clk_io = FLASH_CLK_IO;
|
||||
psram_io.flash_cs_io = FLASH_CS_IO;
|
||||
psram_io.flash_spiq_sd0_io = FLASH_SPIQ_SD0_IO;
|
||||
psram_io.flash_spid_sd1_io = FLASH_SPID_SD1_IO;
|
||||
psram_io.flash_spiwp_sd3_io = FLASH_SPIWP_SD3_IO;
|
||||
psram_io.flash_spihd_sd2_io = FLASH_SPIHD_SD2_IO;
|
||||
psram_io.psram_clk_io = PSRAM_CLK_IO;
|
||||
psram_io.psram_cs_io = PSRAM_CS_IO;
|
||||
psram_io.psram_spiq_sd0_io = PSRAM_SPIQ_SD0_IO;
|
||||
psram_io.psram_spid_sd1_io = PSRAM_SPID_SD1_IO;
|
||||
psram_io.psram_spiwp_sd3_io = PSRAM_SPIWP_SD3_IO;
|
||||
psram_io.psram_spihd_sd2_io = PSRAM_SPIHD_SD2_IO;
|
||||
}
|
||||
|
||||
WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(PSRAM_CLK_IO) | BIT(PSRAM_CS_IO)); //DISABLE OUPUT FOR IO16/17
|
||||
WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(psram_io.psram_clk_io) | BIT(psram_io.psram_cs_io)); //DISABLE OUPUT FOR IO16/17
|
||||
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
|
||||
s_psram_mode = mode;
|
||||
|
||||
periph_module_enable(PERIPH_SPI_MODULE);
|
||||
|
||||
WRITE_PERI_REG(SPI_EXT3_REG(0), 0x1);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_USR_PREP_HOLD_M);
|
||||
|
||||
psram_spi_init(PSRAM_SPI_1, mode);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
|
||||
gpio_matrix_out(psram_io.psram_cs_io, SPICS1_OUT_IDX, 0, 0);
|
||||
switch (mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
psram_spi_init(PSRAM_SPI_1, mode);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
|
||||
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(psram_io.psram_clk_io, SPICLK_OUT_IDX, 0, 0);
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
psram_spi_init(PSRAM_SPI_1, mode);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
|
||||
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
|
||||
/* We need to delay CLK to the PSRAM with respect to the clock signal as output by the SPI peripheral.
|
||||
We do this by routing it signal to signal 224/225, which are used as a loopback; the extra run through
|
||||
the GPIO matrix causes the delay. We use GPIO20 (which is not in any package but has pad logic in
|
||||
silicon) as a temporary pad for this. So the signal path is:
|
||||
SPI CLK --> GPIO28 --> signal224(in then out) --> internal GPIO29 --> signal225(in then out) --> GPIO17(PSRAM CLK)
|
||||
*/
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_28, SPICLK_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(PSRAM_INTERNAL_IO_28, SIG_IN_FUNC224_IDX, 0);
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_IN_FUNC224_IDX, 0, 0);
|
||||
gpio_matrix_in(PSRAM_INTERNAL_IO_29, SIG_IN_FUNC225_IDX, 0);
|
||||
gpio_matrix_out(PSRAM_CLK_IO, SIG_IN_FUNC225_IDX, 0, 0);
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
/* We need to delay CLK to the PSRAM with respect to the clock signal as output by the SPI peripheral.
|
||||
We do this by routing it signal to signal 224/225, which are used as a loopback; the extra run through
|
||||
the GPIO matrix causes the delay. We use GPIO20 (which is not in any package but has pad logic in
|
||||
silicon) as a temporary pad for this. So the signal path is:
|
||||
SPI CLK --> GPIO28 --> signal224(in then out) --> internal GPIO29 --> signal225(in then out) --> GPIO17(PSRAM CLK)
|
||||
*/
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_28, SPICLK_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(PSRAM_INTERNAL_IO_28, SIG_IN_FUNC224_IDX, 0);
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_IN_FUNC224_IDX, 0, 0);
|
||||
gpio_matrix_in(PSRAM_INTERNAL_IO_29, SIG_IN_FUNC225_IDX, 0);
|
||||
gpio_matrix_out(psram_io.psram_clk_io, SIG_IN_FUNC225_IDX, 0, 0);
|
||||
} else {
|
||||
gpio_matrix_out(psram_io.psram_clk_io, SPICLK_OUT_IDX, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V
|
||||
@ -591,10 +692,10 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
}
|
||||
#endif
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_SETUP_M);
|
||||
psram_gpio_config(mode);
|
||||
WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(PSRAM_CS_IO)| BIT(PSRAM_CLK_IO));
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], PIN_FUNC_GPIO);
|
||||
psram_gpio_config(psram_io, mode);
|
||||
WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(psram_io.psram_cs_io) | BIT(psram_io.psram_clk_io));
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.psram_cs_io], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.psram_clk_io], PIN_FUNC_GPIO);
|
||||
|
||||
psram_read_id(&s_psram_id);
|
||||
if (!PSRAM_IS_VALID(s_psram_id)) {
|
||||
@ -603,22 +704,17 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
uint32_t flash_id = g_rom_flashchip.device_id;
|
||||
if (flash_id == FLASH_ID_GD25LQ32C) {
|
||||
// Set drive ability for 1.8v flash in 80Mhz.
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CS_IO], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_spiq_sd0_io], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_spid_sd1_io], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_spihd_sd2_io], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_spiwp_sd3_io], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_cs_io], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.flash_clk_io], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.psram_cs_io], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[psram_io.psram_clk_io], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
}
|
||||
if (PSRAM_IS_64MBIT(s_psram_id)) {
|
||||
// For this psram, we don't need any extra clock cycles after cs get back to high level
|
||||
s_clk_mode = PSRAM_CLK_MODE_NORM;
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
|
||||
} else if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
|
||||
|
||||
if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
|
||||
s_clk_mode = PSRAM_CLK_MODE_DCLK;
|
||||
if (mode == PSRAM_CACHE_F80M_S80M) {
|
||||
/* note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram, VSPI port will be
|
||||
@ -630,7 +726,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
if (!r) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(psram_io.psram_clk_io, PSRAM_CLK_SIGNAL, 0, 0);
|
||||
//use spi3 clock,but use spi1 data/cs wires
|
||||
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
|
||||
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
|
||||
@ -646,7 +742,14 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For other psram, we don't need any extra clock cycles after cs get back to high level
|
||||
s_clk_mode = PSRAM_CLK_MODE_NORM;
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(psram_io.psram_clk_io, SPICLK_OUT_IDX, 0, 0);
|
||||
}
|
||||
|
||||
psram_enable_qio_mode(PSRAM_SPI_1);
|
||||
psram_cache_init(mode, vaddrmode);
|
||||
return ESP_OK;
|
||||
|
@ -27,8 +27,9 @@ typedef enum {
|
||||
} psram_cache_mode_t;
|
||||
|
||||
typedef enum {
|
||||
PSRAM_SIZE_32MBITS = 0,
|
||||
PSRAM_SIZE_64MBITS = 1,
|
||||
PSRAM_SIZE_16MBITS = 0,
|
||||
PSRAM_SIZE_32MBITS = 1,
|
||||
PSRAM_SIZE_64MBITS = 2,
|
||||
PSRAM_SIZE_MAX,
|
||||
} psram_size_t;
|
||||
|
||||
|
@ -279,8 +279,7 @@ void IRAM_ATTR esp_restart_noos()
|
||||
rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_200ns);
|
||||
rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_200ns);
|
||||
rtc_wdt_set_time(RTC_WDT_STAGE0, 1000);
|
||||
rtc_wdt_enable();
|
||||
rtc_wdt_protect_on();
|
||||
rtc_wdt_flashboot_mode_enable();
|
||||
|
||||
// Reset and stall the other CPU.
|
||||
// CPU must be reset before stalling, in case it was running a s32c1i
|
||||
|
71
components/esp32/test/test_backtrace.c
Normal file
71
components/esp32/test/test_backtrace.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Note: Currently, the backtraces must still be checked manually. Therefore,
|
||||
* these test cases should always pass.
|
||||
* Todo: Automate the checking of backtrace addresses.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#define SW_ISR_LEVEL_1 7
|
||||
#define SW_ISR_LEVEL_3 29
|
||||
#define RECUR_DEPTH 3
|
||||
#define ACTION_ABORT -1
|
||||
#define ACTION_INT_WDT -2
|
||||
|
||||
// Set to (-1) for abort(), (-2) for interrupt watchdog
|
||||
static int backtrace_trigger_source;
|
||||
|
||||
/*
|
||||
* Recursive functions to generate a longer call stack. When the max specified
|
||||
* recursion depth is reached, the following actions can be taken.
|
||||
*/
|
||||
static void __attribute__((__noinline__)) recursive_func(int recur_depth, int action)
|
||||
{
|
||||
if (recur_depth > 1) {
|
||||
recursive_func(recur_depth - 1, action);
|
||||
} else if (action >= 0) {
|
||||
xt_set_intset(1 << action);
|
||||
} else if (action == ACTION_ABORT) {
|
||||
abort();
|
||||
// Todo: abort() causes problems in GDB Stub backtrace due to being 'non returning'.
|
||||
} else if (action == ACTION_INT_WDT) {
|
||||
portDISABLE_INTERRUPTS();
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void level_three_isr (void *arg)
|
||||
{
|
||||
xt_set_intclear(1 << SW_ISR_LEVEL_3); //Clear interrupt
|
||||
recursive_func(RECUR_DEPTH, backtrace_trigger_source); //Abort at the max recursive depth
|
||||
}
|
||||
|
||||
static void level_one_isr(void *arg)
|
||||
{
|
||||
xt_set_intclear(1 << SW_ISR_LEVEL_1); //Clear interrupt
|
||||
recursive_func(RECUR_DEPTH, SW_ISR_LEVEL_3); //Trigger nested interrupt max recursive depth
|
||||
}
|
||||
|
||||
TEST_CASE("Test backtrace from abort", "[reset_reason][reset=abort,SW_CPU_RESET]")
|
||||
{
|
||||
//Allocate level one and three SW interrupts
|
||||
esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, 0, level_one_isr, NULL, NULL); //Level 1 SW intr
|
||||
esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, 0, level_three_isr, NULL, NULL); //Level 3 SW intr
|
||||
backtrace_trigger_source = ACTION_ABORT;
|
||||
recursive_func(RECUR_DEPTH, SW_ISR_LEVEL_1); //Trigger lvl 1 SW interrupt at max recursive depth
|
||||
}
|
||||
|
||||
TEST_CASE("Test backtrace from interrupt watchdog timeout", "[reset_reason][reset=Interrupt wdt timeout on CPU0,SW_CPU_RESET]")
|
||||
{
|
||||
//Allocate level one and three SW interrupts
|
||||
esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, 0, level_one_isr, NULL, NULL); //Level 1 SW intr
|
||||
esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, 0, level_three_isr, NULL, NULL); //Level 3 SW intr
|
||||
backtrace_trigger_source = ACTION_INT_WDT;
|
||||
recursive_func(RECUR_DEPTH, SW_ISR_LEVEL_1); //Trigger lvl 1 SW interrupt at max recursive depth
|
||||
}
|
90
components/esp32/test/test_phy_rtc.c
Normal file
90
components/esp32/test/test_phy_rtc.c
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Tests for the Wi-Fi
|
||||
*/
|
||||
#include "string.h"
|
||||
#include "esp_system.h"
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
|
||||
//Function just extern, need not test
|
||||
extern void bt_bb_init_cmplx(void);
|
||||
extern void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
extern void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
|
||||
//Functions in librtc.a called by WIFI or Blutooth directly in ISR
|
||||
extern void bt_bb_init_cmplx_reg(void);
|
||||
extern void force_wifi_mode(int);
|
||||
extern void unforce_wifi_mode(void);
|
||||
extern void bt_track_pll_cap(void);
|
||||
|
||||
static const char* TAG = "test_phy_rtc";
|
||||
|
||||
static SemaphoreHandle_t semphr_done;
|
||||
|
||||
//Functions in libphy.a called by WIFI or Blutooth directly in ISR
|
||||
static void test_phy_rtc_init(void)
|
||||
{
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_LOGI(TAG, "no free pages or nvs version mismatch, erase..");
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
TEST_ESP_OK(ret);
|
||||
|
||||
esp_phy_load_cal_and_init(PHY_BT_MODULE);
|
||||
esp_phy_load_cal_and_init(PHY_WIFI_MODULE);
|
||||
|
||||
//must run here, not blocking in above code
|
||||
TEST_ASSERT(1);
|
||||
}
|
||||
|
||||
static IRAM_ATTR void test_phy_rtc_cache_task(void *arg)
|
||||
{
|
||||
test_phy_rtc_init();
|
||||
|
||||
ESP_LOGI(TAG, "Test bt_bb_init_cmplx_reg()...");
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
bt_bb_init_cmplx_reg();
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
ESP_LOGI(TAG, "Test force_wifi_mode(%d)...", i);
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
force_wifi_mode(i);
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
|
||||
ESP_LOGI(TAG, "Test unforce_wifi_mode()...");
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
unforce_wifi_mode();
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Test bt_track_pll_cap()...");
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
bt_track_pll_cap();
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
|
||||
TEST_ASSERT( xSemaphoreGive(semphr_done) );
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test PHY/RTC functions called when cache is disabled", "[phy_rtc][cache_disabled]")
|
||||
{
|
||||
semphr_done = xSemaphoreCreateCounting(1, 0);
|
||||
|
||||
xTaskCreatePinnedToCore(test_phy_rtc_cache_task, "phy_rtc_test_task", 2048,
|
||||
NULL, configMAX_PRIORITIES-1, NULL, 0);
|
||||
|
||||
TEST_ASSERT( xSemaphoreTake(semphr_done, portMAX_DELAY) );
|
||||
|
||||
vSemaphoreDelete(semphr_done);
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "test_utils.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
static const char* TAG = "test_wifi";
|
||||
|
||||
@ -121,3 +122,68 @@ TEST_CASE("wifi stop and deinit","[wifi]")
|
||||
|
||||
TEST_IGNORE_MESSAGE("this test case is ignored due to the critical memory leak of tcpip_adapter and event_loop.");
|
||||
}
|
||||
|
||||
static void start_wifi_as_softap(void)
|
||||
{
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
cfg.nvs_enable = false;
|
||||
|
||||
wifi_config_t w_config = {
|
||||
.ap.ssid = "default_ssid",
|
||||
.ap.password = "default_password",
|
||||
.ap.ssid_len = 0,
|
||||
.ap.channel = 1,
|
||||
.ap.authmode = WIFI_AUTH_WPA2_PSK,
|
||||
.ap.ssid_hidden = false,
|
||||
.ap.max_connection = 4,
|
||||
.ap.beacon_interval = 100,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(esp_wifi_init(&cfg));
|
||||
TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_AP));
|
||||
TEST_ESP_OK(esp_wifi_set_config(WIFI_IF_AP, &w_config));
|
||||
TEST_ESP_OK(esp_wifi_start());
|
||||
|
||||
}
|
||||
|
||||
static void stop_wifi(void)
|
||||
{
|
||||
TEST_ESP_OK(esp_wifi_stop());
|
||||
TEST_ESP_OK(esp_wifi_deinit());
|
||||
}
|
||||
|
||||
static void receive_ds2ds_packet(void)
|
||||
{
|
||||
start_wifi_as_softap();
|
||||
unity_wait_for_signal("sender ready");
|
||||
unity_send_signal("receiver ready");
|
||||
|
||||
// wait for sender to send packets
|
||||
vTaskDelay(1000/portTICK_PERIOD_MS);
|
||||
stop_wifi();
|
||||
|
||||
}
|
||||
|
||||
static const char ds2ds_pdu[] = {
|
||||
0x48, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xE8, 0x65, 0xD4, 0xCB, 0x74, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x60, 0x94, 0xE8, 0x65, 0xD4, 0xCB, 0x74, 0x1C, 0x26, 0xB9,
|
||||
0x0D, 0x02, 0x7D, 0x13, 0x00, 0x00, 0x01, 0xE8, 0x65, 0xD4, 0xCB, 0x74,
|
||||
0x1C, 0x00, 0x00, 0x26, 0xB9, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static void send_ds2ds_packet(void)
|
||||
{
|
||||
start_wifi_as_softap();
|
||||
unity_send_signal("sender ready");
|
||||
unity_wait_for_signal("receiver ready");
|
||||
|
||||
// send packet 20 times to make sure receiver will get this packet
|
||||
for (uint16_t i = 0; i < 20; i++) {
|
||||
esp_wifi_80211_tx(ESP_IF_WIFI_AP, ds2ds_pdu, sizeof(ds2ds_pdu), true);
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
}
|
||||
stop_wifi();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("receive ds2ds packet without exception", "[wifi][test_env=UT_T2_1]", receive_ds2ds_packet, send_ds2ds_packet);
|
||||
|
@ -286,7 +286,7 @@ static esp_event_base_instance_t* loop_find_event_base_instance(esp_event_loop_i
|
||||
// Functions that operate on post instance
|
||||
static esp_err_t post_instance_create(esp_event_base_t event_base, int32_t event_id, void* event_data, int32_t event_data_size, esp_event_post_instance_t* post)
|
||||
{
|
||||
void** event_data_copy = NULL;
|
||||
void* event_data_copy = NULL;
|
||||
|
||||
// Make persistent copy of event data on heap.
|
||||
if (event_data != NULL && event_data_size != 0) {
|
||||
@ -528,6 +528,8 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
|
||||
exec |= true;
|
||||
}
|
||||
|
||||
post_instance_delete(&post);
|
||||
|
||||
if (ticks_to_run != portMAX_DELAY) {
|
||||
end = xTaskGetTickCount();
|
||||
remaining_ticks -= end - marker;
|
||||
@ -559,10 +561,14 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop)
|
||||
|
||||
esp_event_loop_instance_t* loop = (esp_event_loop_instance_t*) event_loop;
|
||||
SemaphoreHandle_t loop_mutex = loop->mutex;
|
||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||
SemaphoreHandle_t loop_profiling_mutex = loop->profiling_mutex;
|
||||
#endif
|
||||
|
||||
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);
|
||||
|
||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||
xSemaphoreTakeRecursive(loop->profiling_mutex, portMAX_DELAY);
|
||||
portENTER_CRITICAL(&s_event_loops_spinlock);
|
||||
SLIST_REMOVE(&s_event_loops, loop, esp_event_loop_instance, loop_entry);
|
||||
portEXIT_CRITICAL(&s_event_loops_spinlock);
|
||||
@ -588,6 +594,10 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop)
|
||||
free(loop);
|
||||
// Free loop mutex before deleting
|
||||
xSemaphoreGiveRecursive(loop_mutex);
|
||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||
xSemaphoreGiveRecursive(loop_profiling_mutex);
|
||||
vSemaphoreDelete(loop_profiling_mutex);
|
||||
#endif
|
||||
vSemaphoreDelete(loop_mutex);
|
||||
|
||||
ESP_LOGD(TAG, "deleted loop %p", (void*) event_loop);
|
||||
|
@ -90,7 +90,7 @@ typedef struct esp_event_loop_instance {
|
||||
typedef struct esp_event_post_instance {
|
||||
esp_event_base_t base; /**< the event base */
|
||||
int32_t id; /**< the event id */
|
||||
void** data; /**< data associated with the event */
|
||||
void* data; /**< data associated with the event */
|
||||
} esp_event_post_instance_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -27,14 +27,19 @@ static const char* TAG = "test_event";
|
||||
|
||||
#define TEST_CONFIG_WAIT_MULTIPLIER 5
|
||||
|
||||
// The initial logging "initializing test" is to ensure mutex allocation is not counted against memory not being freed
|
||||
// during teardown.
|
||||
#define TEST_SETUP() \
|
||||
ESP_LOGI(TAG, "initializing test"); \
|
||||
size_t free_mem_before = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); \
|
||||
test_setup(); \
|
||||
s_test_core_id = xPortGetCoreID(); \
|
||||
s_test_priority = uxTaskPriorityGet(NULL); \
|
||||
s_test_priority = uxTaskPriorityGet(NULL);
|
||||
|
||||
#define TEST_TEARDOWN() \
|
||||
test_teardown(); \
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_INT_WDT_TIMEOUT_MS * TEST_CONFIG_WAIT_MULTIPLIER));
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_INT_WDT_TIMEOUT_MS * TEST_CONFIG_WAIT_MULTIPLIER)); \
|
||||
TEST_ASSERT_EQUAL(free_mem_before, heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
|
||||
|
||||
typedef struct {
|
||||
void* data;
|
||||
@ -679,6 +684,10 @@ static void loop_run_task(void* args)
|
||||
|
||||
static void performance_test(bool dedicated_task)
|
||||
{
|
||||
// rand() seems to do a one-time allocation. Call it here so that the memory it allocates
|
||||
// is not counted as a leak.
|
||||
unsigned int _rand __attribute__((unused)) = rand();
|
||||
|
||||
TEST_SETUP();
|
||||
|
||||
const char test_base[] = "qwertyuiopasdfghjklzxvbnmmnbvcxzqwertyuiopasdfghjklzxvbnmmnbvcxz";
|
||||
@ -775,6 +784,14 @@ static void performance_test(bool dedicated_task)
|
||||
|
||||
int average = (int) (running_sum / (running_count));
|
||||
|
||||
if (!dedicated_task) {
|
||||
((esp_event_loop_instance_t*) loop)->task = mtask;
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete(loop));
|
||||
|
||||
TEST_TEARDOWN();
|
||||
|
||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||
ESP_LOGI(TAG, "events dispatched/second with profiling enabled: %d", average);
|
||||
// Enabling profiling will slow down event dispatch, so the set threshold
|
||||
@ -786,14 +803,6 @@ static void performance_test(bool dedicated_task)
|
||||
TEST_PERFORMANCE_GREATER_THAN(EVENT_DISPATCH_PSRAM, "%d", average);
|
||||
#endif // CONFIG_SPIRAM_SUPPORT
|
||||
#endif // CONFIG_EVENT_LOOP_PROFILING
|
||||
|
||||
if (!dedicated_task) {
|
||||
((esp_event_loop_instance_t*) loop)->task = mtask;
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete(loop));
|
||||
|
||||
TEST_TEARDOWN();
|
||||
}
|
||||
|
||||
TEST_CASE("performance test - dedicated task", "[event]")
|
||||
|
@ -166,7 +166,7 @@ enum HttpStatus_Code
|
||||
};
|
||||
|
||||
|
||||
static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client);
|
||||
static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len);
|
||||
static esp_err_t esp_http_client_connect(esp_http_client_handle_t client);
|
||||
static esp_err_t esp_http_client_send_post_data(esp_http_client_handle_t client);
|
||||
|
||||
@ -817,7 +817,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
|
||||
}
|
||||
/* falls through */
|
||||
case HTTP_STATE_CONNECTED:
|
||||
if ((err = esp_http_client_request_send(client)) != ESP_OK) {
|
||||
if ((err = esp_http_client_request_send(client, client->post_len)) != ESP_OK) {
|
||||
if (client->is_async && errno == EAGAIN) {
|
||||
return ESP_ERR_HTTP_EAGAIN;
|
||||
}
|
||||
@ -997,11 +997,11 @@ static int http_client_prepare_first_line(esp_http_client_handle_t client, int w
|
||||
return first_line_len;
|
||||
}
|
||||
|
||||
static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client)
|
||||
static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len)
|
||||
{
|
||||
int first_line_len = 0;
|
||||
if (!client->first_line_prepared) {
|
||||
if ((first_line_len = http_client_prepare_first_line(client, client->post_len)) < 0) {
|
||||
if ((first_line_len = http_client_prepare_first_line(client, write_len)) < 0) {
|
||||
return first_line_len;
|
||||
}
|
||||
client->first_line_prepared = true;
|
||||
@ -1092,7 +1092,7 @@ esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len)
|
||||
if ((err = esp_http_client_connect(client)) != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if ((err = esp_http_client_request_send(client)) != ESP_OK) {
|
||||
if ((err = esp_http_client_request_send(client, write_len)) != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
|
@ -27,6 +27,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
note: esp_https_server.h includes a customized copy of this
|
||||
initializer that should be kept in sync
|
||||
*/
|
||||
#define HTTPD_DEFAULT_CONFIG() { \
|
||||
.task_priority = tskIDLE_PRIORITY+5, \
|
||||
.stack_size = 4096, \
|
||||
@ -39,7 +43,13 @@ extern "C" {
|
||||
.lru_purge_enable = false, \
|
||||
.recv_wait_timeout = 5, \
|
||||
.send_wait_timeout = 5, \
|
||||
};
|
||||
.global_user_ctx = NULL, \
|
||||
.global_user_ctx_free_fn = NULL, \
|
||||
.global_transport_ctx = NULL, \
|
||||
.global_transport_ctx_free_fn = NULL, \
|
||||
.open_fn = NULL, \
|
||||
.close_fn = NULL, \
|
||||
}
|
||||
|
||||
#define ESP_ERR_HTTPD_BASE (0x8000) /*!< Starting number of HTTPD error codes */
|
||||
#define ESP_ERR_HTTPD_HANDLERS_FULL (ESP_ERR_HTTPD_BASE + 1) /*!< All slots for registering URI handlers have been consumed */
|
||||
@ -70,6 +80,35 @@ typedef void* httpd_handle_t;
|
||||
*/
|
||||
typedef enum http_method httpd_method_t;
|
||||
|
||||
/**
|
||||
* @brief Prototype for freeing context data (if any)
|
||||
* @param[in] ctx : object to free
|
||||
*/
|
||||
typedef void (*httpd_free_ctx_fn_t)(void *ctx);
|
||||
|
||||
/**
|
||||
* @brief Function prototype for opening a session.
|
||||
*
|
||||
* Called immediately after the socket was opened to set up the send/recv functions and
|
||||
* other parameters of the socket.
|
||||
*
|
||||
* @param[in] hd : server instance
|
||||
* @param[in] sockfd : session socket file descriptor
|
||||
* @return status
|
||||
*/
|
||||
typedef esp_err_t (*httpd_open_func_t)(httpd_handle_t hd, int sockfd);
|
||||
|
||||
/**
|
||||
* @brief Function prototype for closing a session.
|
||||
*
|
||||
* @note It's possible that the socket descriptor is invalid at this point, the function
|
||||
* is called for all terminated sessions. Ensure proper handling of return codes.
|
||||
*
|
||||
* @param[in] hd : server instance
|
||||
* @param[in] sockfd : session socket file descriptor
|
||||
*/
|
||||
typedef void (*httpd_close_func_t)(httpd_handle_t hd, int sockfd);
|
||||
|
||||
/**
|
||||
* @brief HTTP Server Configuration Structure
|
||||
*
|
||||
@ -99,6 +138,63 @@ typedef struct httpd_config {
|
||||
bool lru_purge_enable; /*!< Purge "Least Recently Used" connection */
|
||||
uint16_t recv_wait_timeout; /*!< Timeout for recv function (in seconds)*/
|
||||
uint16_t send_wait_timeout; /*!< Timeout for send function (in seconds)*/
|
||||
|
||||
/**
|
||||
* Global user context.
|
||||
*
|
||||
* This field can be used to store arbitrary user data within the server context.
|
||||
* The value can be retrieved using the server handle, available e.g. in the httpd_req_t struct.
|
||||
*
|
||||
* When shutting down, the server frees up the user context by
|
||||
* calling free() on the global_user_ctx field. If you wish to use a custom
|
||||
* function for freeing the global user context, please specify that here.
|
||||
*/
|
||||
void * global_user_ctx;
|
||||
|
||||
/**
|
||||
* Free function for global user context
|
||||
*/
|
||||
httpd_free_ctx_fn_t global_user_ctx_free_fn;
|
||||
|
||||
/**
|
||||
* Global transport context.
|
||||
*
|
||||
* Similar to global_user_ctx, but used for session encoding or encryption (e.g. to hold the SSL context).
|
||||
* It will be freed using free(), unless global_transport_ctx_free_fn is specified.
|
||||
*/
|
||||
void * global_transport_ctx;
|
||||
|
||||
/**
|
||||
* Free function for global transport context
|
||||
*/
|
||||
httpd_free_ctx_fn_t global_transport_ctx_free_fn;
|
||||
|
||||
/**
|
||||
* Custom session opening callback.
|
||||
*
|
||||
* Called on a new session socket just after accept(), but before reading any data.
|
||||
*
|
||||
* This is an opportunity to set up e.g. SSL encryption using global_transport_ctx
|
||||
* and the send/recv/pending session overrides.
|
||||
*
|
||||
* If a context needs to be maintained between these functions, store it in the session using
|
||||
* httpd_sess_set_transport_ctx() and retrieve it later with httpd_sess_get_transport_ctx()
|
||||
*/
|
||||
httpd_open_func_t open_fn;
|
||||
|
||||
/**
|
||||
* Custom session closing callback.
|
||||
*
|
||||
* Called when a session is deleted, before freeing user and transport contexts and before
|
||||
* closing the socket. This is a place for custom de-init code common to all sockets.
|
||||
*
|
||||
* Set the user or transport context to NULL if it was freed here, so the server does not
|
||||
* try to free it again.
|
||||
*
|
||||
* This function is run for all terminated sessions, including sessions where the socket
|
||||
* was closed by the network stack - that is, the file descriptor may not be valid anymore.
|
||||
*/
|
||||
httpd_close_func_t close_fn;
|
||||
} httpd_config_t;
|
||||
|
||||
/**
|
||||
@ -180,11 +276,6 @@ esp_err_t httpd_stop(httpd_handle_t handle);
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Function type for freeing context data (if any)
|
||||
*/
|
||||
typedef void (*httpd_free_sess_ctx_fn_t)(void *sess_ctx);
|
||||
|
||||
/* Max supported HTTP request header length */
|
||||
#define HTTPD_MAX_REQ_HDR_LEN CONFIG_HTTPD_MAX_REQ_HDR_LEN
|
||||
|
||||
@ -232,7 +323,7 @@ typedef struct httpd_req {
|
||||
* calling free() on the sess_ctx member. If you wish to use a custom
|
||||
* function for freeing the session context, please specify that here.
|
||||
*/
|
||||
httpd_free_sess_ctx_fn_t free_ctx;
|
||||
httpd_free_ctx_fn_t free_ctx;
|
||||
} httpd_req_t;
|
||||
|
||||
/**
|
||||
@ -360,13 +451,18 @@ esp_err_t httpd_unregister_uri(httpd_handle_t handle, const char* uri);
|
||||
* HTTPD_SOCK_ERR_ codes, which will eventually be conveyed as
|
||||
* return value of httpd_send() function
|
||||
*
|
||||
* @param[in] hd : server instance
|
||||
* @param[in] sockfd : session socket file descriptor
|
||||
* @param[in] buf : buffer with bytes to send
|
||||
* @param[in] buf_len : data size
|
||||
* @param[in] flags : flags for the send() function
|
||||
* @return
|
||||
* - Bytes : The number of bytes sent successfully
|
||||
* - HTTPD_SOCK_ERR_INVALID : Invalid arguments
|
||||
* - HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket send()
|
||||
* - HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket send()
|
||||
*/
|
||||
typedef int (*httpd_send_func_t)(int sockfd, const char *buf, size_t buf_len, int flags);
|
||||
typedef int (*httpd_send_func_t)(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags);
|
||||
|
||||
/**
|
||||
* @brief Prototype for HTTPDs low-level recv function
|
||||
@ -376,6 +472,11 @@ typedef int (*httpd_send_func_t)(int sockfd, const char *buf, size_t buf_len, in
|
||||
* HTTPD_SOCK_ERR_ codes, which will eventually be conveyed as
|
||||
* return value of httpd_req_recv() function
|
||||
*
|
||||
* @param[in] hd : server instance
|
||||
* @param[in] sockfd : session socket file descriptor
|
||||
* @param[in] buf : buffer with bytes to send
|
||||
* @param[in] buf_len : data size
|
||||
* @param[in] flags : flags for the send() function
|
||||
* @return
|
||||
* - Bytes : The number of bytes received successfully
|
||||
* - 0 : Buffer length parameter is zero / connection closed by peer
|
||||
@ -383,7 +484,25 @@ typedef int (*httpd_send_func_t)(int sockfd, const char *buf, size_t buf_len, in
|
||||
* - HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket recv()
|
||||
* - HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket recv()
|
||||
*/
|
||||
typedef int (*httpd_recv_func_t)(int sockfd, char *buf, size_t buf_len, int flags);
|
||||
typedef int (*httpd_recv_func_t)(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags);
|
||||
|
||||
/**
|
||||
* @brief Prototype for HTTPDs low-level "get pending bytes" function
|
||||
*
|
||||
* @note User specified pending function must handle errors internally,
|
||||
* depending upon the set value of errno, and return specific
|
||||
* HTTPD_SOCK_ERR_ codes, which will be handled accordingly in
|
||||
* the server task.
|
||||
*
|
||||
* @param[in] hd : server instance
|
||||
* @param[in] sockfd : session socket file descriptor
|
||||
* @return
|
||||
* - Bytes : The number of bytes waiting to be received
|
||||
* - HTTPD_SOCK_ERR_INVALID : Invalid arguments
|
||||
* - HTTPD_SOCK_ERR_TIMEOUT : Timeout/interrupted while calling socket pending()
|
||||
* - HTTPD_SOCK_ERR_FAIL : Unrecoverable error while calling socket pending()
|
||||
*/
|
||||
typedef int (*httpd_pending_func_t)(httpd_handle_t hd, int sockfd);
|
||||
|
||||
/** End of TX / RX
|
||||
* @}
|
||||
@ -398,42 +517,64 @@ typedef int (*httpd_recv_func_t)(int sockfd, char *buf, size_t buf_len, int flag
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Override web server's receive function
|
||||
* @brief Override web server's receive function (by session FD)
|
||||
*
|
||||
* This function overrides the web server's receive function. This same function is
|
||||
* used to read and parse HTTP headers as well as body.
|
||||
* used to read HTTP request packets.
|
||||
*
|
||||
* @note This API is supposed to be called only from the context of
|
||||
* a URI handler where httpd_req_t* request pointer is valid.
|
||||
* @note This API is supposed to be called either from the context of
|
||||
* - an http session APIs where sockfd is a valid parameter
|
||||
* - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
|
||||
*
|
||||
* @param[in] r The request being responded to
|
||||
* @param[in] recv_func The receive function to be set for this request
|
||||
* @param[in] hd HTTPD instance handle
|
||||
* @param[in] sockfd Session socket FD
|
||||
* @param[in] recv_func The receive function to be set for this session
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : On successfully registering override
|
||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
||||
*/
|
||||
esp_err_t httpd_set_recv_override(httpd_req_t *r, httpd_recv_func_t recv_func);
|
||||
esp_err_t httpd_sess_set_recv_override(httpd_handle_t hd, int sockfd, httpd_recv_func_t recv_func);
|
||||
|
||||
/**
|
||||
* @brief Override web server's send function
|
||||
* @brief Override web server's send function (by session FD)
|
||||
*
|
||||
* This function overrides the web server's send function. This same function is
|
||||
* used to send out any response to any HTTP request.
|
||||
*
|
||||
* @note This API is supposed to be called only from the context of
|
||||
* a URI handler where httpd_req_t* request pointer is valid.
|
||||
* @note This API is supposed to be called either from the context of
|
||||
* - an http session APIs where sockfd is a valid parameter
|
||||
* - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
|
||||
*
|
||||
* @param[in] r The request being responded to
|
||||
* @param[in] send_func The send function to be set for this request
|
||||
* @param[in] hd HTTPD instance handle
|
||||
* @param[in] sockfd Session socket FD
|
||||
* @param[in] send_func The send function to be set for this session
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : On successfully registering override
|
||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
||||
*/
|
||||
esp_err_t httpd_set_send_override(httpd_req_t *r, httpd_send_func_t send_func);
|
||||
esp_err_t httpd_sess_set_send_override(httpd_handle_t hd, int sockfd, httpd_send_func_t send_func);
|
||||
|
||||
/**
|
||||
* @brief Override web server's pending function (by session FD)
|
||||
*
|
||||
* This function overrides the web server's pending function. This function is
|
||||
* used to test for pending bytes in a socket.
|
||||
*
|
||||
* @note This API is supposed to be called either from the context of
|
||||
* - an http session APIs where sockfd is a valid parameter
|
||||
* - a URI handler where sockfd is obtained using httpd_req_to_sockfd()
|
||||
*
|
||||
* @param[in] hd HTTPD instance handle
|
||||
* @param[in] sockfd Session socket FD
|
||||
* @param[in] pending_func The receive function to be set for this session
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : On successfully registering override
|
||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||
*/
|
||||
esp_err_t httpd_sess_set_pending_override(httpd_handle_t hd, int sockfd, httpd_pending_func_t pending_func);
|
||||
|
||||
/**
|
||||
* @brief Get the Socket Descriptor from the HTTP request
|
||||
@ -443,7 +584,7 @@ esp_err_t httpd_set_send_override(httpd_req_t *r, httpd_send_func_t send_func);
|
||||
* This is useful when user wants to call functions that require
|
||||
* session socket fd, from within a URI handler, ie. :
|
||||
* httpd_sess_get_ctx(),
|
||||
* httpd_trigger_sess_close(),
|
||||
* httpd_sess_trigger_close(),
|
||||
* httpd_sess_update_timestamp().
|
||||
*
|
||||
* @note This API is supposed to be called only from the context of
|
||||
@ -631,7 +772,7 @@ esp_err_t httpd_query_key_value(const char *qry, const char *key, char *val, siz
|
||||
*
|
||||
* @param[in] r The request being responded to
|
||||
* @param[in] buf Buffer from where the content is to be fetched
|
||||
* @param[in] buf_len Length of the buffer
|
||||
* @param[in] buf_len Length of the buffer, -1 to use strlen()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : On successfully sending the response packet
|
||||
@ -640,7 +781,7 @@ esp_err_t httpd_query_key_value(const char *qry, const char *key, char *val, siz
|
||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
|
||||
*/
|
||||
esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len);
|
||||
esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len);
|
||||
|
||||
/**
|
||||
* @brief API to send one HTTP chunk
|
||||
@ -670,7 +811,7 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len);
|
||||
*
|
||||
* @param[in] r The request being responded to
|
||||
* @param[in] buf Pointer to a buffer that stores the data
|
||||
* @param[in] buf_len Length of the data from the buffer that should be sent out
|
||||
* @param[in] buf_len Length of the data from the buffer that should be sent out, -1 to use strlen()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : On successfully sending the response packet chunk
|
||||
@ -679,7 +820,7 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len);
|
||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
||||
*/
|
||||
esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, size_t buf_len);
|
||||
esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len);
|
||||
|
||||
/* Some commonly used status codes */
|
||||
#define HTTPD_200 "200 OK" /*!< HTTP Response 200 */
|
||||
@ -901,6 +1042,57 @@ int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len);
|
||||
*/
|
||||
void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd);
|
||||
|
||||
/**
|
||||
* @brief Set session context by socket descriptor
|
||||
*
|
||||
* @param[in] handle Handle to server returned by httpd_start
|
||||
* @param[in] sockfd The socket descriptor for which the context should be extracted.
|
||||
* @param[in] ctx Context object to assign to the session
|
||||
* @param[in] free_fn Function that should be called to free the context
|
||||
*/
|
||||
void httpd_sess_set_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn);
|
||||
|
||||
/**
|
||||
* @brief Get session 'transport' context by socket descriptor
|
||||
* @see httpd_sess_get_ctx()
|
||||
*
|
||||
* This context is used by the send/receive functions, for example to manage SSL context.
|
||||
*
|
||||
* @param[in] handle Handle to server returned by httpd_start
|
||||
* @param[in] sockfd The socket descriptor for which the context should be extracted.
|
||||
* @return
|
||||
* - void* : Pointer to the transport context associated with this session
|
||||
* - NULL : Empty context / Invalid handle / Invalid socket fd
|
||||
*/
|
||||
void *httpd_sess_get_transport_ctx(httpd_handle_t handle, int sockfd);
|
||||
|
||||
/**
|
||||
* @brief Set session 'transport' context by socket descriptor
|
||||
* @see httpd_sess_set_ctx()
|
||||
*
|
||||
* @param[in] handle Handle to server returned by httpd_start
|
||||
* @param[in] sockfd The socket descriptor for which the context should be extracted.
|
||||
* @param[in] ctx Transport context object to assign to the session
|
||||
* @param[in] free_fn Function that should be called to free the transport context
|
||||
*/
|
||||
void httpd_sess_set_transport_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn);
|
||||
|
||||
/**
|
||||
* @brief Get HTTPD global user context (it was set in the server config struct)
|
||||
*
|
||||
* @param[in] handle Handle to server returned by httpd_start
|
||||
* @return global user context
|
||||
*/
|
||||
void *httpd_get_global_user_ctx(httpd_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Get HTTPD global transport context (it was set in the server config struct)
|
||||
*
|
||||
* @param[in] handle Handle to server returned by httpd_start
|
||||
* @return global transport context
|
||||
*/
|
||||
void *httpd_get_global_transport_ctx(httpd_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Trigger an httpd session close externally
|
||||
*
|
||||
@ -916,7 +1108,7 @@ void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd);
|
||||
* - ESP_ERR_NOT_FOUND : Socket fd not found
|
||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||
*/
|
||||
esp_err_t httpd_trigger_sess_close(httpd_handle_t handle, int sockfd);
|
||||
esp_err_t httpd_sess_trigger_close(httpd_handle_t handle, int sockfd);
|
||||
|
||||
/**
|
||||
* @brief Update timestamp for a given socket
|
||||
|
@ -118,10 +118,13 @@ typedef enum {
|
||||
struct sock_db {
|
||||
int fd; /*!< The file descriptor for this socket */
|
||||
void *ctx; /*!< A custom context for this socket */
|
||||
void *transport_ctx; /*!< A custom 'transport' context for this socket, to be used by send/recv/pending */
|
||||
httpd_handle_t handle; /*!< Server handle */
|
||||
httpd_free_sess_ctx_fn_t free_ctx; /*!< Function for freeing the context */
|
||||
httpd_free_ctx_fn_t free_ctx; /*!< Function for freeing the context */
|
||||
httpd_free_ctx_fn_t free_transport_ctx; /*!< Function for freeing the 'transport' context */
|
||||
httpd_send_func_t send_fn; /*!< Send function for this socket */
|
||||
httpd_recv_func_t recv_fn; /*!< Send function for this socket */
|
||||
httpd_recv_func_t recv_fn; /*!< Receive function for this socket */
|
||||
httpd_pending_func_t pending_fn; /*!< Pending function for this socket */
|
||||
int64_t timestamp; /*!< Timestamp indicating when the socket was last used */
|
||||
char pending_data[PARSER_BLOCK_SIZE]; /*!< Buffer for pending data to be received */
|
||||
size_t pending_len; /*!< Length of pending data to be received */
|
||||
@ -169,6 +172,23 @@ struct httpd_data {
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Retrieve a session by its descriptor
|
||||
*
|
||||
* @param[in] hd Server instance data
|
||||
* @param[in] sockfd Socket FD
|
||||
* @return pointer into the socket DB, or NULL if not found
|
||||
*/
|
||||
struct sock_db *httpd_sess_get(struct httpd_data *hd, int sockfd);
|
||||
|
||||
/**
|
||||
* @brief Delete sessions whose FDs have became invalid.
|
||||
* This is a recovery strategy e.g. after select() fails.
|
||||
*
|
||||
* @param[in] hd Server instance data
|
||||
*/
|
||||
void httpd_sess_delete_invalid(struct httpd_data *hd);
|
||||
|
||||
/**
|
||||
* @brief Initializes an http session by resetting the sockets database.
|
||||
*
|
||||
@ -220,6 +240,14 @@ esp_err_t httpd_sess_process(struct httpd_data *hd, int clifd);
|
||||
*/
|
||||
int httpd_sess_delete(struct httpd_data *hd, int clifd);
|
||||
|
||||
/**
|
||||
* @brief Free session context
|
||||
*
|
||||
* @param[in] ctx Pointer to session context
|
||||
* @param[in] free_fn Free function to call on session context
|
||||
*/
|
||||
void httpd_sess_free_ctx(void *ctx, httpd_free_ctx_fn_t free_fn);
|
||||
|
||||
/**
|
||||
* @brief Add descriptors present in the socket database to an fd_set and
|
||||
* update the value of maxfd which are needed by the select function
|
||||
@ -331,7 +359,16 @@ void httpd_unregister_all_uri_handlers(struct httpd_data *hd);
|
||||
* - true : if valid request
|
||||
* - false : otherwise
|
||||
*/
|
||||
bool httpd_valid_req(httpd_req_t *r);
|
||||
bool httpd_validate_req_ptr(httpd_req_t *r);
|
||||
|
||||
/* httpd_validate_req_ptr() adds some overhead to frequently used APIs,
|
||||
* and is useful mostly for debugging, so it's preferable to disable
|
||||
* the check by defaut and enable it only if necessary */
|
||||
#ifdef CONFIG_HTTPD_VALIDATE_REQ
|
||||
#define httpd_valid_req(r) httpd_validate_req_ptr(r)
|
||||
#else
|
||||
#define httpd_valid_req(r) true
|
||||
#endif
|
||||
|
||||
/** End of Group : URI Handling
|
||||
* @}
|
||||
@ -454,6 +491,7 @@ size_t httpd_unrecv(struct httpd_req *r, const char *buf, size_t buf_len);
|
||||
* NEVER be called directly. The semantics of this is exactly similar to
|
||||
* send() of the BSD socket API.
|
||||
*
|
||||
* @param[in] hd Server instance data
|
||||
* @param[in] sockfd Socket descriptor for sending data
|
||||
* @param[in] buf Pointer to the buffer from where the body of the response is taken
|
||||
* @param[in] buf_len Length of the buffer
|
||||
@ -463,13 +501,14 @@ size_t httpd_unrecv(struct httpd_req *r, const char *buf, size_t buf_len);
|
||||
* - Length of data : if successful
|
||||
* - -1 : if failed (appropriate errno is set)
|
||||
*/
|
||||
int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags);
|
||||
int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags);
|
||||
|
||||
/**
|
||||
* @brief This is the low level default recv function of the HTTPD. This should
|
||||
* NEVER be called directly. The semantics of this is exactly similar to
|
||||
* recv() of the BSD socket API.
|
||||
*
|
||||
* @param[in] hd Server instance data
|
||||
* @param[in] sockfd Socket descriptor for sending data
|
||||
* @param[out] buf Pointer to the buffer which will be filled with the received data
|
||||
* @param[in] buf_len Length of the buffer
|
||||
@ -479,7 +518,7 @@ int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags);
|
||||
* - Length of data : if successful
|
||||
* - -1 : if failed (appropriate errno is set)
|
||||
*/
|
||||
int httpd_default_recv(int sockfd, char *buf, size_t buf_len, int flags);
|
||||
int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags);
|
||||
|
||||
/** End of Group : Send and Receive
|
||||
* @}
|
||||
|
@ -62,8 +62,8 @@ static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd)
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv));
|
||||
|
||||
if (httpd_sess_new(hd, new_fd)) {
|
||||
ESP_LOGW(TAG, LOG_FMT("no slots left for launching new session"));
|
||||
if (ESP_OK != httpd_sess_new(hd, new_fd)) {
|
||||
ESP_LOGW(TAG, LOG_FMT("session creation failed"));
|
||||
close(new_fd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@ -102,6 +102,16 @@ esp_err_t httpd_queue_work(httpd_handle_t handle, httpd_work_fn_t work, void *ar
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void *httpd_get_global_user_ctx(httpd_handle_t handle)
|
||||
{
|
||||
return ((struct httpd_data *)handle)->config.global_user_ctx;
|
||||
}
|
||||
|
||||
void *httpd_get_global_transport_ctx(httpd_handle_t handle)
|
||||
{
|
||||
return ((struct httpd_data *)handle)->config.global_transport_ctx;
|
||||
}
|
||||
|
||||
static void httpd_close_all_sessions(struct httpd_data *hd)
|
||||
{
|
||||
int fd = -1;
|
||||
@ -159,11 +169,8 @@ static esp_err_t httpd_server(struct httpd_data *hd)
|
||||
int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL);
|
||||
if (active_cnt < 0) {
|
||||
ESP_LOGE(TAG, LOG_FMT("error in select (%d)"), errno);
|
||||
/* Assert, as it's not possible to recover from this point onwards,
|
||||
* and there is no way to notify the main thread that server handle
|
||||
* has become invalid */
|
||||
assert(false);
|
||||
return ESP_FAIL;
|
||||
httpd_sess_delete_invalid(hd);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Case0: Do we have a control message? */
|
||||
@ -367,7 +374,27 @@ esp_err_t httpd_stop(httpd_handle_t handle)
|
||||
|
||||
ESP_LOGD(TAG, LOG_FMT("sent control msg to stop server"));
|
||||
while (hd->hd_td.status != THREAD_STOPPED) {
|
||||
httpd_os_thread_sleep(1000);
|
||||
httpd_os_thread_sleep(100);
|
||||
}
|
||||
|
||||
/* Release global user context, if not NULL */
|
||||
if (hd->config.global_user_ctx) {
|
||||
if (hd->config.global_user_ctx_free_fn) {
|
||||
hd->config.global_user_ctx_free_fn(hd->config.global_user_ctx);
|
||||
} else {
|
||||
free(hd->config.global_user_ctx);
|
||||
}
|
||||
hd->config.global_user_ctx = NULL;
|
||||
}
|
||||
|
||||
/* Release global transport context, if not NULL */
|
||||
if (hd->config.global_transport_ctx) {
|
||||
if (hd->config.global_transport_ctx_free_fn) {
|
||||
hd->config.global_transport_ctx_free_fn(hd->config.global_transport_ctx);
|
||||
} else {
|
||||
free(hd->config.global_transport_ctx);
|
||||
}
|
||||
hd->config.global_transport_ctx = NULL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, LOG_FMT("server stopped"));
|
||||
|
@ -552,6 +552,24 @@ static void init_req_aux(struct httpd_req_aux *ra, httpd_config_t *config)
|
||||
memset(ra->resp_hdrs, 0, config->max_resp_headers * sizeof(struct resp_hdr));
|
||||
}
|
||||
|
||||
static void httpd_req_cleanup(httpd_req_t *r)
|
||||
{
|
||||
struct httpd_req_aux *ra = r->aux;
|
||||
|
||||
/* Retrieve session info from the request into the socket database */
|
||||
if (ra->sd->ctx != r->sess_ctx) {
|
||||
/* Free previous context */
|
||||
httpd_sess_free_ctx(ra->sd->ctx, ra->sd->free_ctx);
|
||||
ra->sd->ctx = r->sess_ctx;
|
||||
}
|
||||
ra->sd->free_ctx = r->free_ctx;
|
||||
|
||||
/* Clear out the request and request_aux structures */
|
||||
ra->sd = NULL;
|
||||
r->handle = NULL;
|
||||
r->aux = NULL;
|
||||
}
|
||||
|
||||
/* Function that processes incoming TCP data and
|
||||
* updates the http request data httpd_req_t
|
||||
*/
|
||||
@ -563,7 +581,7 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
|
||||
r->handle = hd;
|
||||
r->aux = &hd->hd_req_aux;
|
||||
/* Associate the request to the socket */
|
||||
struct httpd_req_aux *ra = r->aux;
|
||||
struct httpd_req_aux *ra = r->aux;
|
||||
ra->sd = sd;
|
||||
/* Set defaults */
|
||||
ra->status = (char *)HTTPD_200;
|
||||
@ -573,7 +591,11 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
|
||||
r->sess_ctx = sd->ctx;
|
||||
r->free_ctx = sd->free_ctx;
|
||||
/* Parse request */
|
||||
return httpd_parse_req(hd);
|
||||
esp_err_t err = httpd_parse_req(hd);
|
||||
if (err != ESP_OK) {
|
||||
httpd_req_cleanup(r);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Function that resets the http request data
|
||||
@ -592,6 +614,7 @@ esp_err_t httpd_req_delete(struct httpd_data *hd)
|
||||
int recv_len = MIN(sizeof(dummy) - 1, ra->remaining_len);
|
||||
int ret = httpd_req_recv(r, dummy, recv_len);
|
||||
if (ret < 0) {
|
||||
httpd_req_cleanup(r);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@ -599,20 +622,14 @@ esp_err_t httpd_req_delete(struct httpd_data *hd)
|
||||
ESP_LOGD(TAG, LOG_FMT("purging data : %s"), dummy);
|
||||
}
|
||||
|
||||
/* Retrieve session info from the request into the socket database */
|
||||
ra->sd->ctx = r->sess_ctx;
|
||||
ra->sd->free_ctx = r->free_ctx;
|
||||
|
||||
/* Clear out the request and request_aux structures */
|
||||
ra->sd = NULL;
|
||||
r->aux = NULL;
|
||||
httpd_req_cleanup(r);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Validates the request to prevent users from calling APIs, that are to
|
||||
* be called only inside URI handler, outside the handler context
|
||||
*/
|
||||
bool httpd_valid_req(httpd_req_t *r)
|
||||
bool httpd_validate_req_ptr(httpd_req_t *r)
|
||||
{
|
||||
if (r) {
|
||||
struct httpd_data *hd = (struct httpd_data *) r->handle;
|
||||
|
@ -33,11 +33,23 @@ bool httpd_is_sess_available(struct httpd_data *hd)
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct sock_db *httpd_sess_get(struct httpd_data *hd, int newfd)
|
||||
struct sock_db *httpd_sess_get(struct httpd_data *hd, int sockfd)
|
||||
{
|
||||
if (hd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if called inside a request handler, and the
|
||||
* session sockfd in use is same as the parameter */
|
||||
if ((hd->hd_req_aux.sd) && (hd->hd_req_aux.sd->fd == sockfd)) {
|
||||
/* Just return the pointer to the sock_db
|
||||
* corresponding to the request */
|
||||
return hd->hd_req_aux.sd;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < hd->config.max_open_sockets; i++) {
|
||||
if (hd->hd_sd[i].fd == newfd) {
|
||||
if (hd->hd_sd[i].fd == sockfd) {
|
||||
return &hd->hd_sd[i];
|
||||
}
|
||||
}
|
||||
@ -61,6 +73,12 @@ esp_err_t httpd_sess_new(struct httpd_data *hd, int newfd)
|
||||
hd->hd_sd[i].handle = (httpd_handle_t) hd;
|
||||
hd->hd_sd[i].send_fn = httpd_default_send;
|
||||
hd->hd_sd[i].recv_fn = httpd_default_recv;
|
||||
|
||||
/* Call user-defined session opening function */
|
||||
if (hd->config.open_fn) {
|
||||
esp_err_t ret = hd->config.open_fn(hd, hd->hd_sd[i].fd);
|
||||
if (ret != ESP_OK) return ret;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
@ -68,21 +86,94 @@ esp_err_t httpd_sess_new(struct httpd_data *hd, int newfd)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
void httpd_sess_free_ctx(void *ctx, httpd_free_ctx_fn_t free_fn)
|
||||
{
|
||||
if (ctx) {
|
||||
if (free_fn) {
|
||||
free_fn(ctx);
|
||||
} else {
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *httpd_sess_get_ctx(httpd_handle_t handle, int sockfd)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct httpd_data *hd = (struct httpd_data *) handle;
|
||||
struct sock_db *sd = httpd_sess_get(hd, sockfd);
|
||||
struct sock_db *sd = httpd_sess_get(handle, sockfd);
|
||||
if (sd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if the function has been called from inside a
|
||||
* request handler, in which case fetch the context from
|
||||
* the httpd_req_t structure */
|
||||
struct httpd_data *hd = (struct httpd_data *) handle;
|
||||
if (hd->hd_req_aux.sd == sd) {
|
||||
return hd->hd_req.sess_ctx;
|
||||
}
|
||||
|
||||
return sd->ctx;
|
||||
}
|
||||
|
||||
void httpd_sess_set_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn)
|
||||
{
|
||||
struct sock_db *sd = httpd_sess_get(handle, sockfd);
|
||||
if (sd == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the function has been called from inside a
|
||||
* request handler, in which case set the context inside
|
||||
* the httpd_req_t structure */
|
||||
struct httpd_data *hd = (struct httpd_data *) handle;
|
||||
if (hd->hd_req_aux.sd == sd) {
|
||||
if (hd->hd_req.sess_ctx != ctx) {
|
||||
/* Don't free previous context if it is in sockdb
|
||||
* as it will be freed inside httpd_req_cleanup() */
|
||||
if (sd->ctx != hd->hd_req.sess_ctx) {
|
||||
/* Free previous context */
|
||||
httpd_sess_free_ctx(hd->hd_req.sess_ctx, hd->hd_req.free_ctx);
|
||||
}
|
||||
hd->hd_req.sess_ctx = ctx;
|
||||
}
|
||||
hd->hd_req.free_ctx = free_fn;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Else set the context inside the sock_db structure */
|
||||
if (sd->ctx != ctx) {
|
||||
/* Free previous context */
|
||||
httpd_sess_free_ctx(sd->ctx, sd->free_ctx);
|
||||
sd->ctx = ctx;
|
||||
}
|
||||
sd->free_ctx = free_fn;
|
||||
}
|
||||
|
||||
void *httpd_sess_get_transport_ctx(httpd_handle_t handle, int sockfd)
|
||||
{
|
||||
struct sock_db *sd = httpd_sess_get(handle, sockfd);
|
||||
if (sd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sd->transport_ctx;
|
||||
}
|
||||
|
||||
void httpd_sess_set_transport_ctx(httpd_handle_t handle, int sockfd, void *ctx, httpd_free_ctx_fn_t free_fn)
|
||||
{
|
||||
struct sock_db *sd = httpd_sess_get(handle, sockfd);
|
||||
if (sd == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sd->transport_ctx != ctx) {
|
||||
/* Free previous transport context */
|
||||
httpd_sess_free_ctx(sd->transport_ctx, sd->free_transport_ctx);
|
||||
sd->transport_ctx = ctx;
|
||||
}
|
||||
sd->free_transport_ctx = free_fn;
|
||||
}
|
||||
|
||||
void httpd_sess_set_descriptors(struct httpd_data *hd,
|
||||
fd_set *fdset, int *maxfd)
|
||||
{
|
||||
@ -98,6 +189,22 @@ void httpd_sess_set_descriptors(struct httpd_data *hd,
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a FD is valid */
|
||||
static int fd_is_valid(int fd)
|
||||
{
|
||||
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
|
||||
}
|
||||
|
||||
void httpd_sess_delete_invalid(struct httpd_data *hd)
|
||||
{
|
||||
for (int i = 0; i < hd->config.max_open_sockets; i++) {
|
||||
if (hd->hd_sd[i].fd != -1 && !fd_is_valid(hd->hd_sd[i].fd)) {
|
||||
ESP_LOGW(TAG, LOG_FMT("Closing invalid socket %d"), hd->hd_sd[i].fd);
|
||||
httpd_sess_delete(hd, hd->hd_sd[i].fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int httpd_sess_delete(struct httpd_data *hd, int fd)
|
||||
{
|
||||
ESP_LOGD(TAG, LOG_FMT("fd = %d"), fd);
|
||||
@ -105,7 +212,12 @@ int httpd_sess_delete(struct httpd_data *hd, int fd)
|
||||
int pre_sess_fd = -1;
|
||||
for (i = 0; i < hd->config.max_open_sockets; i++) {
|
||||
if (hd->hd_sd[i].fd == fd) {
|
||||
hd->hd_sd[i].fd = -1;
|
||||
/* global close handler */
|
||||
if (hd->config.close_fn) {
|
||||
hd->config.close_fn(hd, fd);
|
||||
}
|
||||
|
||||
/* release 'user' context */
|
||||
if (hd->hd_sd[i].ctx) {
|
||||
if (hd->hd_sd[i].free_ctx) {
|
||||
hd->hd_sd[i].free_ctx(hd->hd_sd[i].ctx);
|
||||
@ -115,6 +227,20 @@ int httpd_sess_delete(struct httpd_data *hd, int fd)
|
||||
hd->hd_sd[i].ctx = NULL;
|
||||
hd->hd_sd[i].free_ctx = NULL;
|
||||
}
|
||||
|
||||
/* release 'transport' context */
|
||||
if (hd->hd_sd[i].transport_ctx) {
|
||||
if (hd->hd_sd[i].free_transport_ctx) {
|
||||
hd->hd_sd[i].free_transport_ctx(hd->hd_sd[i].transport_ctx);
|
||||
} else {
|
||||
free(hd->hd_sd[i].transport_ctx);
|
||||
}
|
||||
hd->hd_sd[i].transport_ctx = NULL;
|
||||
hd->hd_sd[i].free_transport_ctx = NULL;
|
||||
}
|
||||
|
||||
/* mark session slot as available */
|
||||
hd->hd_sd[i].fd = -1;
|
||||
break;
|
||||
} else if (hd->hd_sd[i].fd != -1) {
|
||||
/* Return the fd just preceding the one being
|
||||
@ -142,6 +268,12 @@ bool httpd_sess_pending(struct httpd_data *hd, int fd)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sd->pending_fn) {
|
||||
// test if there's any data to be read (besides read() function, which is handled by select() in the main httpd loop)
|
||||
// this should check e.g. for the SSL data buffer
|
||||
if (sd->pending_fn(hd, fd) > 0) return true;
|
||||
}
|
||||
|
||||
return (sd->pending_len != 0);
|
||||
}
|
||||
|
||||
@ -206,7 +338,7 @@ esp_err_t httpd_sess_close_lru(struct httpd_data *hd)
|
||||
}
|
||||
}
|
||||
ESP_LOGD(TAG, LOG_FMT("fd = %d"), lru_fd);
|
||||
return httpd_trigger_sess_close(hd, lru_fd);
|
||||
return httpd_sess_trigger_close(hd, lru_fd);
|
||||
}
|
||||
|
||||
int httpd_sess_iterate(struct httpd_data *hd, int start_fd)
|
||||
@ -243,14 +375,9 @@ static void httpd_sess_close(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t httpd_trigger_sess_close(httpd_handle_t handle, int sockfd)
|
||||
esp_err_t httpd_sess_trigger_close(httpd_handle_t handle, int sockfd)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
struct httpd_data *hd = (struct httpd_data *) handle;
|
||||
struct sock_db *sock_db = httpd_sess_get(hd, sockfd);
|
||||
struct sock_db *sock_db = httpd_sess_get(handle, sockfd);
|
||||
if (sock_db) {
|
||||
return httpd_queue_work(handle, httpd_sess_close, sock_db);
|
||||
}
|
||||
|
@ -22,33 +22,33 @@
|
||||
|
||||
static const char *TAG = "httpd_txrx";
|
||||
|
||||
esp_err_t httpd_set_send_override(httpd_req_t *r, httpd_send_func_t send_func)
|
||||
esp_err_t httpd_sess_set_send_override(httpd_handle_t hd, int sockfd, httpd_send_func_t send_func)
|
||||
{
|
||||
if (r == NULL || send_func == NULL) {
|
||||
struct sock_db *sess = httpd_sess_get(hd, sockfd);
|
||||
if (!sess) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!httpd_valid_req(r)) {
|
||||
return ESP_ERR_HTTPD_INVALID_REQ;
|
||||
}
|
||||
|
||||
struct httpd_req_aux *ra = r->aux;
|
||||
ra->sd->send_fn = send_func;
|
||||
sess->send_fn = send_func;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t httpd_set_recv_override(httpd_req_t *r, httpd_recv_func_t recv_func)
|
||||
esp_err_t httpd_sess_set_recv_override(httpd_handle_t hd, int sockfd, httpd_recv_func_t recv_func)
|
||||
{
|
||||
if (r == NULL || recv_func == NULL) {
|
||||
struct sock_db *sess = httpd_sess_get(hd, sockfd);
|
||||
if (!sess) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
sess->recv_fn = recv_func;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
if (!httpd_valid_req(r)) {
|
||||
return ESP_ERR_HTTPD_INVALID_REQ;
|
||||
esp_err_t httpd_sess_set_pending_override(httpd_handle_t hd, int sockfd, httpd_pending_func_t pending_func)
|
||||
{
|
||||
struct sock_db *sess = httpd_sess_get(hd, sockfd);
|
||||
if (!sess) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
struct httpd_req_aux *ra = r->aux;
|
||||
ra->sd->recv_fn = recv_func;
|
||||
sess->pending_fn = pending_func;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len)
|
||||
}
|
||||
|
||||
struct httpd_req_aux *ra = r->aux;
|
||||
int ret = ra->sd->send_fn(ra->sd->fd, buf, buf_len, 0);
|
||||
int ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
|
||||
if (ret < 0) {
|
||||
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
|
||||
return ret;
|
||||
@ -77,7 +77,7 @@ static esp_err_t httpd_send_all(httpd_req_t *r, const char *buf, size_t buf_len)
|
||||
int ret;
|
||||
|
||||
while (buf_len > 0) {
|
||||
ret = ra->sd->send_fn(ra->sd->fd, buf, buf_len, 0);
|
||||
ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
|
||||
if (ret < 0) {
|
||||
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
|
||||
return ESP_FAIL;
|
||||
@ -125,7 +125,7 @@ int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_aft
|
||||
}
|
||||
|
||||
/* Receive data of remaining length */
|
||||
int ret = ra->sd->recv_fn(ra->sd->fd, buf, buf_len, 0);
|
||||
int ret = ra->sd->recv_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
|
||||
if (ret < 0) {
|
||||
ESP_LOGD(TAG, LOG_FMT("error in recv_fn"));
|
||||
if ((ret == HTTPD_SOCK_ERR_TIMEOUT) && (pending_len != 0)) {
|
||||
@ -231,7 +231,7 @@ esp_err_t httpd_resp_set_type(httpd_req_t *r, const char *type)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len)
|
||||
esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len)
|
||||
{
|
||||
if (r == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@ -246,6 +246,8 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len)
|
||||
const char *colon_separator = ": ";
|
||||
const char *cr_lf_seperator = "\r\n";
|
||||
|
||||
if (buf_len == -1) buf_len = strlen(buf);
|
||||
|
||||
/* Request headers are no longer available */
|
||||
ra->req_hdrs_count = 0;
|
||||
|
||||
@ -294,7 +296,7 @@ esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, size_t buf_len)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, size_t buf_len)
|
||||
esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len)
|
||||
{
|
||||
if (r == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@ -304,6 +306,8 @@ esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, size_t buf_len)
|
||||
return ESP_ERR_HTTPD_INVALID_REQ;
|
||||
}
|
||||
|
||||
if (buf_len == -1) buf_len = strlen(buf);
|
||||
|
||||
struct httpd_req_aux *ra = r->aux;
|
||||
const char *httpd_chunked_hdr_str = "HTTP/1.1 %s\r\nContent-Type: %s\r\nTransfer-Encoding: chunked\r\n";
|
||||
const char *colon_separator = ": ";
|
||||
@ -359,7 +363,7 @@ esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, size_t buf_len)
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
if (httpd_send_all(r, buf, buf_len) != ESP_OK) {
|
||||
if (httpd_send_all(r, buf, (size_t) buf_len) != ESP_OK) {
|
||||
return ESP_ERR_HTTPD_RESP_SEND;
|
||||
}
|
||||
}
|
||||
@ -520,8 +524,9 @@ static int httpd_sock_err(const char *ctx, int sockfd)
|
||||
return errval;
|
||||
}
|
||||
|
||||
int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags)
|
||||
int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags)
|
||||
{
|
||||
(void)hd;
|
||||
if (buf == NULL) {
|
||||
return HTTPD_SOCK_ERR_INVALID;
|
||||
}
|
||||
@ -533,8 +538,9 @@ int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int httpd_default_recv(int sockfd, char *buf, size_t buf_len, int flags)
|
||||
int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags)
|
||||
{
|
||||
(void)hd;
|
||||
if (buf == NULL) {
|
||||
return HTTPD_SOCK_ERR_INVALID;
|
||||
}
|
||||
|
@ -201,8 +201,10 @@ esp_err_t httpd_uri(struct httpd_data *hd)
|
||||
if (uri == NULL) {
|
||||
switch (err) {
|
||||
case HTTPD_404_NOT_FOUND:
|
||||
ESP_LOGW(TAG, LOG_FMT("URI '%s' not found"), req->uri);
|
||||
return httpd_resp_send_err(req, HTTPD_404_NOT_FOUND);
|
||||
case HTTPD_405_METHOD_NOT_ALLOWED:
|
||||
ESP_LOGW(TAG, LOG_FMT("Method '%d' not allowed for URI '%s'"), req->method, req->uri);
|
||||
return httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED);
|
||||
default:
|
||||
return ESP_FAIL;
|
||||
|
Submodule components/esptool_py/esptool updated: 9fbe1eec65...9ad444a6e0
@ -2,7 +2,8 @@ set(COMPONENT_SRCS "emac_dev.c"
|
||||
"emac_main.c"
|
||||
"eth_phy/phy_common.c"
|
||||
"eth_phy/phy_lan8720.c"
|
||||
"eth_phy/phy_tlk110.c")
|
||||
"eth_phy/phy_tlk110.c"
|
||||
"eth_phy/phy_ip101.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include")
|
||||
|
||||
set(COMPONENT_REQUIRES)
|
||||
|
@ -1,60 +1,55 @@
|
||||
menu Ethernet
|
||||
|
||||
config DMA_RX_BUF_NUM
|
||||
int "Number of DMA RX buffers"
|
||||
range 3 20
|
||||
default 10
|
||||
help
|
||||
Number of DMA receive buffers. Each buffer is 1600 bytes.
|
||||
Buffers are allocated statically.
|
||||
Larger number of buffers increases throughput.
|
||||
If enable flow ctrl, the num must be above 9 .
|
||||
config DMA_RX_BUF_NUM
|
||||
int "Number of DMA RX buffers"
|
||||
range 3 20
|
||||
default 10
|
||||
help
|
||||
Number of DMA receive buffers. Each buffer is 1600 bytes.
|
||||
These buffers are allocated dynamically.
|
||||
More buffers will increase throughput.
|
||||
If flow ctrl is enabled, make sure this number is larger than 9.
|
||||
|
||||
config DMA_TX_BUF_NUM
|
||||
int "Number of DMA TX buffers"
|
||||
range 3 20
|
||||
default 10
|
||||
help
|
||||
Number of DMA transmit buffers. Each buffer is 1600 bytes.
|
||||
Buffers are allocated statically.
|
||||
Larger number of buffers increases throughput.
|
||||
config DMA_TX_BUF_NUM
|
||||
int "Number of DMA TX buffers"
|
||||
range 3 20
|
||||
default 10
|
||||
help
|
||||
Number of DMA transmit buffers. Each buffer is 1600 bytes.
|
||||
These buffers are allocated dynamically.
|
||||
More buffers will increase throughput.
|
||||
|
||||
config EMAC_L2_TO_L3_RX_BUF_MODE
|
||||
bool "Enable copy between Layer2 and Layer3"
|
||||
default n
|
||||
help
|
||||
If this options is selected, a copy of each received buffer will be created when
|
||||
passing it from the Ethernet MAC (L2) to the IP stack (L3). Otherwise, IP stack
|
||||
will receive pointers to the DMA buffers used by Ethernet MAC.
|
||||
config EMAC_L2_TO_L3_RX_BUF_MODE
|
||||
bool "Enable received buffers be copied to Layer3 from Layer2"
|
||||
default y
|
||||
help
|
||||
If this option is selected, a copy of each received buffer will be allocated from the heap
|
||||
before passing it to the IP Layer (L3).
|
||||
Which means, the total amount of received buffers is limited by the heap size.
|
||||
|
||||
When Ethernet MAC doesn't have any unused buffers left, it will drop incoming
|
||||
packets (flow control may help with this problem, to some extent).
|
||||
If this option is not selected, IP layer only uses the pointers to the DMA buffers owned by Ethernet MAC.
|
||||
When Ethernet MAC doesn't have any available buffers left, it will drop the incoming packets.
|
||||
|
||||
The buffers for the IP stack are allocated from the heap, so the total number of
|
||||
receive buffers is limited by the available heap size, if this option is selected.
|
||||
config EMAC_CHECK_LINK_PERIOD_MS
|
||||
int "Period (ms) of checking Ethernet linkup status"
|
||||
range 1000 5000
|
||||
default 2000
|
||||
help
|
||||
The emac driver uses an internal timer to check the Ethernet linkup status.
|
||||
Here you should choose a valid interval time.
|
||||
|
||||
If unsure, choose n.
|
||||
config EMAC_TASK_PRIORITY
|
||||
int "EMAC_TASK_PRIORITY"
|
||||
default 20
|
||||
range 3 22
|
||||
help
|
||||
Priority of Ethernet MAC task.
|
||||
|
||||
config EMAC_CHECK_LINK_PERIOD_MS
|
||||
int "Period(ms) of checking Ethernet linkup status"
|
||||
range 1000 5000
|
||||
default 2000
|
||||
help
|
||||
The emac driver uses an internal timer to check the ethernet linkup
|
||||
status. Here you should choose a valid the interval time.
|
||||
|
||||
config EMAC_TASK_PRIORITY
|
||||
int "EMAC_TASK_PRIORITY"
|
||||
default 20
|
||||
range 3 22
|
||||
help
|
||||
Ethernet MAC task priority.
|
||||
|
||||
config EMAC_TASK_STACK_SIZE
|
||||
int "Stack Size of EMAC Task"
|
||||
default 3072
|
||||
range 2000 8000
|
||||
help
|
||||
Stack Size of Ethernet MAC task.
|
||||
config EMAC_TASK_STACK_SIZE
|
||||
int "Stack Size of EMAC Task"
|
||||
default 3072
|
||||
range 2000 8000
|
||||
help
|
||||
Stack Size of Ethernet MAC task.
|
||||
|
||||
endmenu
|
||||
|
@ -15,16 +15,13 @@
|
||||
#ifndef _EMAC_COMMON_H_
|
||||
#define _EMAC_COMMON_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "emac_dev.h"
|
||||
#include "esp_eth.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_eth.h"
|
||||
#include "emac_dev.h"
|
||||
|
||||
typedef uint32_t emac_sig_t;
|
||||
typedef uint32_t emac_par_t;
|
||||
|
||||
@ -75,8 +72,8 @@ struct emac_config_data {
|
||||
eth_phy_get_duplex_mode_func emac_phy_get_duplex_mode;
|
||||
bool emac_flow_ctrl_enable;
|
||||
bool emac_flow_ctrl_partner_support;
|
||||
eth_phy_get_partner_pause_enable_func emac_phy_get_partner_pause_enable;
|
||||
eth_phy_power_enable_func emac_phy_power_enable;
|
||||
eth_phy_get_partner_pause_enable_func emac_phy_get_partner_pause_enable;
|
||||
eth_phy_power_enable_func emac_phy_power_enable;
|
||||
uint32_t reset_timeout_ms;
|
||||
};
|
||||
|
||||
@ -107,17 +104,15 @@ struct emac_close_cmd {
|
||||
#define DMA_RX_BUF_NUM CONFIG_DMA_RX_BUF_NUM
|
||||
#define DMA_TX_BUF_NUM CONFIG_DMA_TX_BUF_NUM
|
||||
#define EMAC_TASK_PRIORITY CONFIG_EMAC_TASK_PRIORITY
|
||||
#define EMAC_TASK_STACK_SIZE CONFIG_EMAC_TASK_STACK_SIZE
|
||||
#define EMAC_TASK_STACK_SIZE CONFIG_EMAC_TASK_STACK_SIZE
|
||||
|
||||
#define DMA_RX_BUF_SIZE 1600
|
||||
#define DMA_TX_BUF_SIZE 1600
|
||||
|
||||
//rest buf num
|
||||
#define FLOW_CONTROL_HIGH_WATERMARK 3
|
||||
//used buf num
|
||||
#define FLOW_CONTROL_LOW_WATERMARK 6
|
||||
#define FLOW_CONTROL_LOW_WATERMARK 6
|
||||
|
||||
#define PHY_LINK_CHECK_NUM 5
|
||||
#define PHY_LINK_CHECK_NUM 5
|
||||
|
||||
#define EMAC_CMD_OK 0
|
||||
#define EMAC_CMD_FAIL -1
|
||||
|
@ -15,12 +15,12 @@
|
||||
#ifndef _EMAC_DESC_H_
|
||||
#define _EMAC_DESC_H_
|
||||
|
||||
#include "soc/soc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "soc/soc.h"
|
||||
|
||||
#define REG_EMAC_DESC_BASE 0
|
||||
#define EMAC_DESC_TDES0_REG (REG_EMAC_DESC_BASE + 0x0000)
|
||||
#define EMAC_DESC_TX_OWN (BIT(31))
|
||||
|
@ -14,8 +14,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/gpio.h"
|
||||
|
||||
@ -98,4 +97,5 @@ void emac_mac_init(void)
|
||||
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACDUPLEX);
|
||||
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACMII);
|
||||
REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACFESPEED);
|
||||
REG_SET_BIT(EMAC_GMACFF_REG, EMAC_PAM);
|
||||
}
|
||||
|
@ -15,13 +15,13 @@
|
||||
#ifndef _EMAC_DEV_H_
|
||||
#define _EMAC_DEV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/emac_reg_v2.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_types.h"
|
||||
#include "soc/emac_reg_v2.h"
|
||||
|
||||
#define EMAC_INTR_ENABLE_BIT (EMAC_DMAIN_TIE | EMAC_DMAIN_RIE | EMAC_DMAIN_RBUE | EMAC_DMAIN_NISE)
|
||||
|
||||
struct dma_desc {
|
||||
@ -37,7 +37,7 @@ typedef struct dma_extended_desc {
|
||||
uint32_t desc5;
|
||||
uint32_t desc6;
|
||||
uint32_t desc7;
|
||||
}dma_extended_desc_t;
|
||||
} dma_extended_desc_t;
|
||||
|
||||
void emac_enable_clk(bool enable);
|
||||
esp_err_t emac_reset(void);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "esp_eth.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_spiram.h"
|
||||
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
@ -59,8 +60,8 @@
|
||||
|
||||
static struct emac_config_data emac_config;
|
||||
|
||||
static dma_extended_desc_t *emac_dma_rx_chain_buf[DMA_RX_BUF_NUM];
|
||||
static dma_extended_desc_t *emac_dma_tx_chain_buf[DMA_TX_BUF_NUM];
|
||||
static dma_extended_desc_t *emac_dma_rx_chain_buf;
|
||||
static dma_extended_desc_t *emac_dma_tx_chain_buf;
|
||||
static uint8_t *emac_dma_rx_buf[DMA_RX_BUF_NUM];
|
||||
static uint8_t *emac_dma_tx_buf[DMA_TX_BUF_NUM];
|
||||
|
||||
@ -72,6 +73,7 @@ static uint8_t emac_sig_cnt[EMAC_SIG_MAX] = {0};
|
||||
static TimerHandle_t emac_timer = NULL;
|
||||
static SemaphoreHandle_t emac_rx_xMutex = NULL;
|
||||
static SemaphoreHandle_t emac_tx_xMutex = NULL;
|
||||
static intr_handle_t eth_intr_handle = NULL;
|
||||
static const char *TAG = "emac";
|
||||
static bool pause_send = false;
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
@ -93,7 +95,7 @@ void esp_eth_get_mac(uint8_t mac[6])
|
||||
|
||||
esp_err_t esp_eth_set_mac(const uint8_t mac[6])
|
||||
{
|
||||
if ((mac[0] & 0x01) == 0) {
|
||||
if (!(mac[0] & 0x01)) {
|
||||
memcpy(&(emac_config.macaddr[0]), mac, 6);
|
||||
return ESP_OK;
|
||||
} else {
|
||||
@ -106,22 +108,20 @@ eth_speed_mode_t esp_eth_get_speed(void)
|
||||
return emac_config.emac_phy_get_speed_mode();
|
||||
}
|
||||
|
||||
static void emac_setup_tx_desc(struct dma_extended_desc *tx_desc, uint32_t size)
|
||||
static void emac_setup_tx_desc(dma_extended_desc_t *tx_desc, uint32_t size)
|
||||
{
|
||||
tx_desc->basic.desc1 = size & 0xfff;
|
||||
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL |
|
||||
EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT |
|
||||
EMAC_DESC_SECOND_ADDR_CHAIN;
|
||||
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT |
|
||||
EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN;
|
||||
}
|
||||
|
||||
static void emac_clean_tx_desc(struct dma_extended_desc *tx_desc)
|
||||
static void emac_clean_tx_desc(dma_extended_desc_t *tx_desc)
|
||||
{
|
||||
tx_desc->basic.desc1 = 0;
|
||||
tx_desc->basic.desc0 = 0;
|
||||
}
|
||||
|
||||
static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc,
|
||||
uint32_t buf_ptr)
|
||||
static void emac_clean_rx_desc(dma_extended_desc_t *rx_desc, uint32_t buf_ptr)
|
||||
{
|
||||
if (buf_ptr != 0) {
|
||||
rx_desc->basic.desc2 = buf_ptr;
|
||||
@ -184,46 +184,46 @@ static void emac_reset_dma_chain(void)
|
||||
static void emac_init_dma_chain(void)
|
||||
{
|
||||
int i;
|
||||
uint32_t dma_phy;
|
||||
dma_extended_desc_t *p = NULL;
|
||||
|
||||
//init tx chain
|
||||
emac_config.dma_etx = emac_dma_tx_chain_buf[0];
|
||||
emac_config.dma_etx = emac_dma_tx_chain_buf;
|
||||
emac_config.cnt_tx = 0;
|
||||
emac_config.cur_tx = 0;
|
||||
emac_config.dirty_tx = 0;
|
||||
|
||||
p = emac_dma_tx_chain_buf[0];
|
||||
dma_phy = (uint32_t)(emac_config.dma_etx);
|
||||
p = emac_config.dma_etx;
|
||||
|
||||
for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++) {
|
||||
dma_phy += sizeof(dma_extended_desc_t);
|
||||
emac_clean_tx_desc(p);
|
||||
/* point to the buffer */
|
||||
p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
|
||||
/* point to next descriptor */
|
||||
p->basic.desc3 = (uint32_t)(emac_dma_tx_chain_buf[i + 1]);
|
||||
p = emac_dma_tx_chain_buf[i + 1];
|
||||
p->basic.desc3 = dma_phy;
|
||||
p++;
|
||||
}
|
||||
emac_clean_tx_desc(p);
|
||||
/* point to the buffer */
|
||||
p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
|
||||
/* point to first descriptor */
|
||||
p->basic.desc3 = (uint32_t)(emac_config.dma_etx);
|
||||
|
||||
//init rx chain
|
||||
emac_config.dma_erx = emac_dma_rx_chain_buf[0];
|
||||
emac_config.dma_erx = emac_dma_rx_chain_buf;
|
||||
emac_config.cnt_rx = 0;
|
||||
emac_config.cur_rx = 0;
|
||||
emac_config.dirty_rx = 0;
|
||||
|
||||
p = emac_dma_rx_chain_buf[0];
|
||||
dma_phy = (uint32_t)(emac_config.dma_erx);
|
||||
p = emac_config.dma_erx;
|
||||
|
||||
for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++) {
|
||||
dma_phy += sizeof(dma_extended_desc_t);
|
||||
emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
|
||||
/* point to the buffer */
|
||||
p->basic.desc3 = (uint32_t)(emac_dma_rx_chain_buf[i + 1]);
|
||||
/* point to next descriptor */
|
||||
p = emac_dma_rx_chain_buf[i + 1];
|
||||
p->basic.desc3 = dma_phy;
|
||||
p++;
|
||||
}
|
||||
/* point to the buffer */
|
||||
|
||||
emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
|
||||
/* point to first descriptor */
|
||||
p->basic.desc3 = (uint32_t)(emac_config.dma_erx);
|
||||
}
|
||||
|
||||
@ -235,8 +235,7 @@ void esp_eth_smi_write(uint32_t reg_num, uint16_t value)
|
||||
}
|
||||
|
||||
REG_WRITE(EMAC_MIIDATA_REG, value);
|
||||
REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) |
|
||||
((phy_num & 0x1f) << 11) | ((0x3) << 2));
|
||||
REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | ((0x3) << 2));
|
||||
|
||||
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
|
||||
}
|
||||
@ -250,8 +249,7 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
|
||||
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
|
||||
}
|
||||
|
||||
REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) |
|
||||
((phy_num & 0x1f) << 11) | (0x3 << 2));
|
||||
REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | (0x3 << 2));
|
||||
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
|
||||
}
|
||||
value = (REG_READ(EMAC_MIIDATA_REG) & 0xffff);
|
||||
@ -259,12 +257,10 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
|
||||
return value;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value,
|
||||
uint16_t value_mask, int timeout_ms)
|
||||
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms)
|
||||
{
|
||||
unsigned start = xTaskGetTickCount();
|
||||
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) /
|
||||
portTICK_PERIOD_MS;
|
||||
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS;
|
||||
uint16_t current_value = 0;
|
||||
|
||||
while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) {
|
||||
@ -327,8 +323,7 @@ static void emac_set_user_config_data(eth_config_t *config)
|
||||
}
|
||||
emac_config.emac_flow_ctrl_enable = false;
|
||||
#endif
|
||||
emac_config.emac_phy_get_partner_pause_enable =
|
||||
config->phy_get_partner_pause_enable;
|
||||
emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable;
|
||||
emac_config.emac_phy_power_enable = config->phy_power_enable;
|
||||
}
|
||||
|
||||
@ -396,8 +391,7 @@ static esp_err_t emac_verify_args(void)
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
|
||||
if (emac_config.emac_flow_ctrl_enable == true &&
|
||||
emac_config.emac_phy_get_partner_pause_enable == NULL) {
|
||||
if (emac_config.emac_flow_ctrl_enable && !emac_config.emac_phy_get_partner_pause_enable) {
|
||||
ESP_LOGE(TAG, "phy get partner pause enable func is null");
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
@ -420,8 +414,8 @@ static void emac_process_tx(void)
|
||||
|
||||
xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY);
|
||||
|
||||
while ((uint32_t)(emac_dma_tx_chain_buf[emac_config.dirty_tx]) != cur_tx_desc) {
|
||||
emac_clean_tx_desc(emac_dma_tx_chain_buf[emac_config.dirty_tx]);
|
||||
while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx])) != cur_tx_desc) {
|
||||
emac_clean_tx_desc(&(emac_config.dma_etx[emac_config.dirty_tx]));
|
||||
emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM;
|
||||
emac_config.cnt_tx--;
|
||||
|
||||
@ -438,20 +432,19 @@ void esp_eth_free_rx_buf(void *buf)
|
||||
{
|
||||
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
|
||||
|
||||
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.cur_rx], (uint32_t)buf);
|
||||
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]), (uint32_t)buf);
|
||||
emac_config.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM;
|
||||
emac_config.cnt_rx--;
|
||||
if (emac_config.cnt_rx < 0) {
|
||||
ESP_LOGE(TAG, "emac rx buf err!!\n");
|
||||
ESP_LOGE(TAG, "emac rx buf err");
|
||||
}
|
||||
emac_poll_rx_cmd();
|
||||
|
||||
xSemaphoreGiveRecursive(emac_rx_xMutex);
|
||||
|
||||
if (emac_config.emac_flow_ctrl_partner_support == true) {
|
||||
if (emac_config.emac_flow_ctrl_partner_support) {
|
||||
portENTER_CRITICAL(&g_emac_mux);
|
||||
if (pause_send == true && emac_config.cnt_rx <
|
||||
FLOW_CONTROL_LOW_WATERMARK) {
|
||||
if (pause_send && emac_config.cnt_rx < FLOW_CONTROL_LOW_WATERMARK) {
|
||||
emac_send_pause_zero_frame_enable();
|
||||
pause_send = false;
|
||||
}
|
||||
@ -463,11 +456,11 @@ static uint32_t IRAM_ATTR emac_get_rxbuf_count_in_intr(void)
|
||||
{
|
||||
uint32_t cnt = 0;
|
||||
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
|
||||
struct dma_extended_desc *cur_desc = (dma_extended_desc_t *)cur_rx_desc;
|
||||
dma_extended_desc_t *cur_desc = (dma_extended_desc_t *)cur_rx_desc;
|
||||
|
||||
while (cur_desc->basic.desc0 == EMAC_DESC_RX_OWN && cnt < DMA_RX_BUF_NUM) {
|
||||
cnt++;
|
||||
cur_desc = (struct dma_extended_desc *)cur_desc->basic.desc3;
|
||||
cur_desc = (dma_extended_desc_t *)cur_desc->basic.desc3;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
@ -480,19 +473,15 @@ static void emac_process_rx(void)
|
||||
}
|
||||
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
|
||||
|
||||
while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc)) {
|
||||
while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc) {
|
||||
//copy data to lwip
|
||||
emac_config.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]),
|
||||
(((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >>
|
||||
EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH),
|
||||
NULL);
|
||||
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
|
||||
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH), NULL);
|
||||
|
||||
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.dirty_rx],
|
||||
(uint32_t)(emac_dma_rx_buf[emac_config.dirty_rx]));
|
||||
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
|
||||
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
|
||||
|
||||
//if open this ,one intr can do many intrs ?
|
||||
cur_rx_desc = emac_read_rx_cur_reg();
|
||||
}
|
||||
|
||||
@ -507,21 +496,16 @@ static void emac_process_rx_unavail(void)
|
||||
|
||||
uint32_t dirty_cnt = 0;
|
||||
while (dirty_cnt < DMA_RX_BUF_NUM) {
|
||||
|
||||
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
|
||||
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
|
||||
break;
|
||||
}
|
||||
|
||||
dirty_cnt++;
|
||||
//copy data to lwip
|
||||
emac_config.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]),
|
||||
(((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >>
|
||||
EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH),
|
||||
NULL);
|
||||
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
|
||||
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH), NULL);
|
||||
|
||||
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.dirty_rx],
|
||||
(uint32_t)(emac_dma_rx_buf[emac_config.dirty_rx]));
|
||||
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
|
||||
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
|
||||
}
|
||||
emac_enable_rx_intr();
|
||||
@ -539,24 +523,20 @@ static void emac_process_rx_unavail(void)
|
||||
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
|
||||
|
||||
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
|
||||
|
||||
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
|
||||
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
|
||||
break;
|
||||
}
|
||||
|
||||
emac_config.cnt_rx++;
|
||||
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
|
||||
ESP_LOGE(TAG, "emac rx unavail buf err !!\n");
|
||||
ESP_LOGE(TAG, "emac rx buf full");
|
||||
}
|
||||
uint32_t tmp_dirty = emac_config.dirty_rx;
|
||||
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
|
||||
|
||||
//copy data to lwip
|
||||
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
|
||||
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
|
||||
EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH),
|
||||
NULL);
|
||||
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
|
||||
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH), NULL);
|
||||
}
|
||||
emac_enable_rx_intr();
|
||||
emac_enable_rx_unavail_intr();
|
||||
@ -573,51 +553,41 @@ static void emac_process_rx(void)
|
||||
|
||||
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
|
||||
|
||||
if (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx])) !=
|
||||
cur_rx_desc) {
|
||||
|
||||
while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc) &&
|
||||
if ((((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc)) {
|
||||
while ((((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc) &&
|
||||
emac_config.cnt_rx < DMA_RX_BUF_NUM) {
|
||||
emac_config.cnt_rx++;
|
||||
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
|
||||
ESP_LOGE(TAG, "emac rx buf err!!\n");
|
||||
ESP_LOGE(TAG, "emac rx buf full");
|
||||
}
|
||||
uint32_t tmp_dirty = emac_config.dirty_rx;
|
||||
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
|
||||
|
||||
//copy data to lwip
|
||||
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
|
||||
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
|
||||
EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH),
|
||||
NULL);
|
||||
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
|
||||
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH), NULL);
|
||||
|
||||
cur_rx_desc = emac_read_rx_cur_reg();
|
||||
}
|
||||
} else {
|
||||
if (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
|
||||
if ((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 &
|
||||
EMAC_DESC_RX_OWN) == 0) {
|
||||
if (!(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN)) {
|
||||
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
|
||||
|
||||
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
|
||||
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
|
||||
break;
|
||||
}
|
||||
|
||||
emac_config.cnt_rx++;
|
||||
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
|
||||
ESP_LOGE(TAG, "emac rx buf err!!!\n");
|
||||
ESP_LOGE(TAG, "emac rx buf full");
|
||||
}
|
||||
uint32_t tmp_dirty = emac_config.dirty_rx;
|
||||
emac_config.dirty_rx = (emac_config.dirty_rx + 1) %
|
||||
DMA_RX_BUF_NUM;
|
||||
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
|
||||
|
||||
//copy data to lwip
|
||||
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
|
||||
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
|
||||
EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH),
|
||||
NULL);
|
||||
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
|
||||
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
|
||||
EMAC_DESC_FRAME_LENGTH), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -638,9 +608,8 @@ static void IRAM_ATTR emac_process_intr(void *arg)
|
||||
|
||||
if (event & EMAC_RECV_INT) {
|
||||
emac_disable_rx_intr();
|
||||
if (emac_config.emac_flow_ctrl_partner_support == true) {
|
||||
if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK &&
|
||||
pause_send == false) {
|
||||
if (emac_config.emac_flow_ctrl_partner_support) {
|
||||
if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && !pause_send) {
|
||||
pause_send = true;
|
||||
emac_send_pause_frame_enable();
|
||||
}
|
||||
@ -661,9 +630,8 @@ static void IRAM_ATTR emac_process_intr(void *arg)
|
||||
static void emac_set_macaddr_reg(void)
|
||||
{
|
||||
REG_SET_FIELD(EMAC_ADDR0HIGH_REG, EMAC_ADDRESS0_HI, (emac_config.macaddr[5] << 8) | (emac_config.macaddr[4]));
|
||||
REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[3] << 24) |
|
||||
(emac_config.macaddr[2] << 16) | (emac_config.macaddr[1] << 8) |
|
||||
(emac_config.macaddr[0]));
|
||||
REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[3] << 24) | (emac_config.macaddr[2] << 16) |
|
||||
(emac_config.macaddr[1] << 8) | (emac_config.macaddr[0]));
|
||||
}
|
||||
|
||||
static void emac_check_phy_init(void)
|
||||
@ -683,8 +651,8 @@ static void emac_check_phy_init(void)
|
||||
emac_disable_flowctrl();
|
||||
emac_config.emac_flow_ctrl_partner_support = false;
|
||||
#else
|
||||
if (emac_config.emac_flow_ctrl_enable == true) {
|
||||
if (emac_config.emac_phy_get_partner_pause_enable() == true &&
|
||||
if (emac_config.emac_flow_ctrl_enable) {
|
||||
if (emac_config.emac_phy_get_partner_pause_enable() &&
|
||||
emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
|
||||
emac_enable_flowctrl();
|
||||
emac_config.emac_flow_ctrl_partner_support = true;
|
||||
@ -706,7 +674,7 @@ static void emac_process_link_updown(bool link_status)
|
||||
|
||||
emac_config.phy_link_up = link_status;
|
||||
|
||||
if (link_status == true) {
|
||||
if (link_status) {
|
||||
emac_check_phy_init();
|
||||
ESP_LOGD(TAG, "eth link_up");
|
||||
emac_enable_dma_tx();
|
||||
@ -741,8 +709,7 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (emac_config.emac_status != EMAC_RUNTIME_START) {
|
||||
ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d",
|
||||
emac_config.emac_status);
|
||||
ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d", emac_config.emac_status);
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
return ret;
|
||||
}
|
||||
@ -754,9 +721,9 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
memcpy(emac_dma_tx_buf[emac_config.cur_tx], buf, size);
|
||||
memcpy((void *)(emac_config.dma_etx[emac_config.cur_tx].basic.desc2), buf, size);
|
||||
|
||||
emac_setup_tx_desc(emac_dma_tx_chain_buf[emac_config.cur_tx], size);
|
||||
emac_setup_tx_desc(&(emac_config.dma_etx[emac_config.cur_tx]), size);
|
||||
|
||||
emac_config.cnt_tx++;
|
||||
emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM;
|
||||
@ -771,7 +738,7 @@ _exit:
|
||||
|
||||
static void emac_init_default_data(void)
|
||||
{
|
||||
memset((uint8_t *)&emac_config, 0, sizeof(struct emac_config_data));
|
||||
memset((void *)&emac_config, 0, sizeof(struct emac_config_data));
|
||||
}
|
||||
|
||||
void emac_process_link_check(void)
|
||||
@ -799,8 +766,7 @@ void emac_link_check_func(void *pv_parameters)
|
||||
static bool emac_link_check_timer_init(void)
|
||||
{
|
||||
emac_timer = xTimerCreate("emac_timer",
|
||||
(CONFIG_EMAC_CHECK_LINK_PERIOD_MS /
|
||||
portTICK_PERIOD_MS),
|
||||
(CONFIG_EMAC_CHECK_LINK_PERIOD_MS / portTICK_PERIOD_MS),
|
||||
pdTRUE,
|
||||
NULL,
|
||||
emac_link_check_func);
|
||||
@ -843,7 +809,6 @@ static void emac_start(void *param)
|
||||
|
||||
ESP_LOGD(TAG, "emac start");
|
||||
cmd->err = EMAC_CMD_OK;
|
||||
emac_enable_clk(true);
|
||||
|
||||
if (emac_reset() != ESP_OK) {
|
||||
return;
|
||||
@ -858,8 +823,6 @@ static void emac_start(void *param)
|
||||
|
||||
emac_mac_init();
|
||||
|
||||
//ptp TODO
|
||||
|
||||
emac_enable_intr();
|
||||
|
||||
emac_config.emac_status = EMAC_RUNTIME_START;
|
||||
@ -869,8 +832,8 @@ static void emac_start(void *param)
|
||||
esp_event_send(&evt);
|
||||
|
||||
//set a timer to check link up status
|
||||
if (emac_link_check_timer_init() == true) {
|
||||
if (emac_link_check_timer_start() != true) {
|
||||
if (emac_link_check_timer_init()) {
|
||||
if (!emac_link_check_timer_start()) {
|
||||
cmd->err = EMAC_CMD_FAIL;
|
||||
emac_link_check_timer_delete();
|
||||
}
|
||||
@ -906,6 +869,7 @@ esp_err_t esp_eth_enable(void)
|
||||
esp_pm_lock_acquire(s_pm_lock);
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
emac_enable_clk(true);
|
||||
/* init phy device */
|
||||
if (emac_config.phy_init() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Initialise PHY device Timeout");
|
||||
@ -913,7 +877,7 @@ esp_err_t esp_eth_enable(void)
|
||||
}
|
||||
|
||||
if (emac_config.emac_status != EMAC_RUNTIME_NOT_INIT) {
|
||||
if (emac_ioctl(SIG_EMAC_START, (emac_par_t)(&post_cmd)) != 0) {
|
||||
if (emac_ioctl(SIG_EMAC_START, (emac_par_t)(&post_cmd))) {
|
||||
open_cmd.err = EMAC_CMD_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -1103,37 +1067,38 @@ esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par)
|
||||
|
||||
esp_err_t esp_eth_init(eth_config_t *config)
|
||||
{
|
||||
/* dynamically alloc memory for ethernet dma */
|
||||
for (int i = 0; i < DMA_RX_BUF_NUM; i++) {
|
||||
emac_dma_rx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), MALLOC_CAP_DMA);
|
||||
emac_dma_rx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_RX_BUF_SIZE, MALLOC_CAP_DMA);
|
||||
}
|
||||
for (int i = 0; i < DMA_TX_BUF_NUM; i++) {
|
||||
emac_dma_tx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), MALLOC_CAP_DMA);
|
||||
emac_dma_tx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_TX_BUF_SIZE, MALLOC_CAP_DMA);
|
||||
}
|
||||
|
||||
esp_event_set_default_eth_handlers();
|
||||
return esp_eth_init_internal(config);
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_init_internal(eth_config_t *config)
|
||||
{
|
||||
int i = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (emac_config.emac_status != EMAC_RUNTIME_NOT_INIT) {
|
||||
goto _exit;
|
||||
goto _initialised;
|
||||
}
|
||||
|
||||
/* dynamically alloc memory for ethernet dma */
|
||||
emac_dma_rx_chain_buf = (dma_extended_desc_t *)heap_caps_malloc(sizeof(dma_extended_desc_t) * DMA_RX_BUF_NUM, MALLOC_CAP_DMA);
|
||||
emac_dma_tx_chain_buf = (dma_extended_desc_t *)heap_caps_malloc(sizeof(dma_extended_desc_t) * DMA_TX_BUF_NUM, MALLOC_CAP_DMA);
|
||||
for (i = 0; i < DMA_RX_BUF_NUM; i++) {
|
||||
emac_dma_rx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_RX_BUF_SIZE, MALLOC_CAP_DMA);
|
||||
}
|
||||
for (i = 0; i < DMA_TX_BUF_NUM; i++) {
|
||||
emac_dma_tx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_TX_BUF_SIZE, MALLOC_CAP_DMA);
|
||||
}
|
||||
|
||||
emac_init_default_data();
|
||||
|
||||
if (config != NULL) {
|
||||
if (config) {
|
||||
emac_set_user_config_data(config);
|
||||
}
|
||||
|
||||
ret = emac_verify_args();
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
goto _exit;
|
||||
goto _verify_err;
|
||||
}
|
||||
|
||||
emac_config.emac_phy_power_enable(true);
|
||||
@ -1142,24 +1107,35 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
|
||||
periph_module_enable(PERIPH_EMAC_MODULE);
|
||||
|
||||
if (emac_config.clock_mode != ETH_CLOCK_GPIO0_IN) {
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
if (esp_spiram_is_initialized()) {
|
||||
ESP_LOGE(TAG, "GPIO16 and GPIO17 has been occupied by PSRAM, Only ETH_CLOCK_GPIO_IN is supported!");
|
||||
ret = ESP_FAIL;
|
||||
goto _verify_err;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "GPIO16/17 is used for clock of EMAC, Please Make Sure you're not using PSRAM.");
|
||||
}
|
||||
#endif
|
||||
// 50 MHz = 40MHz * (6 + 4) / (2 * (2 + 2) = 400MHz / 8
|
||||
rtc_clk_apll_enable(1, 0, 0, 6, 2);
|
||||
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_H_DIV_NUM, 0);
|
||||
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_DIV_NUM, 0);
|
||||
|
||||
if (emac_config.clock_mode == ETH_CLOCK_GPIO16_OUT) {
|
||||
if (emac_config.clock_mode == ETH_CLOCK_GPIO0_OUT) {
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
REG_WRITE(PIN_CTRL, 6);
|
||||
ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO0");
|
||||
} else if (emac_config.clock_mode == ETH_CLOCK_GPIO16_OUT) {
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
|
||||
ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO16");
|
||||
} else if (emac_config.clock_mode == ETH_CLOCK_GPIO17_OUT) {
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U,
|
||||
FUNC_GPIO17_EMAC_CLK_OUT_180);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
|
||||
ESP_LOGD(TAG, "EMAC 50MHz inverted clock output on GPIO17");
|
||||
}
|
||||
}
|
||||
|
||||
emac_enable_clk(true);
|
||||
REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL,
|
||||
EMAC_EX_PHY_INTF_RMII);
|
||||
REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII);
|
||||
emac_dma_init();
|
||||
|
||||
if (emac_config.clock_mode == ETH_CLOCK_GPIO0_IN) {
|
||||
@ -1191,21 +1167,47 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
|
||||
emac_rx_xMutex = xSemaphoreCreateRecursiveMutex();
|
||||
emac_tx_xMutex = xSemaphoreCreateRecursiveMutex();
|
||||
emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t));
|
||||
xTaskCreate(emac_task, "emacT", EMAC_TASK_STACK_SIZE, NULL,
|
||||
EMAC_TASK_PRIORITY, &emac_task_hdl);
|
||||
xTaskCreate(emac_task,
|
||||
"emacT",
|
||||
EMAC_TASK_STACK_SIZE,
|
||||
NULL,
|
||||
EMAC_TASK_PRIORITY,
|
||||
&emac_task_hdl);
|
||||
|
||||
esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL);
|
||||
esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, ð_intr_handle);
|
||||
|
||||
emac_config.emac_status = EMAC_RUNTIME_INIT;
|
||||
|
||||
_exit:
|
||||
return ESP_OK;
|
||||
|
||||
_verify_err:
|
||||
free(emac_dma_rx_chain_buf);
|
||||
free(emac_dma_tx_chain_buf);
|
||||
emac_dma_rx_chain_buf = NULL;
|
||||
emac_dma_tx_chain_buf = NULL;
|
||||
for (i = 0; i < DMA_RX_BUF_NUM; i++) {
|
||||
free(emac_dma_rx_buf[i]);
|
||||
emac_dma_rx_buf[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < DMA_TX_BUF_NUM; i++) {
|
||||
free(emac_dma_tx_buf[i]);
|
||||
emac_dma_tx_buf[i] = NULL;
|
||||
}
|
||||
_initialised:
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_deinit(void)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
int i = 0;
|
||||
|
||||
if (emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
|
||||
goto _exit;
|
||||
}
|
||||
if (emac_config.emac_status == EMAC_RUNTIME_START) {
|
||||
esp_eth_disable();
|
||||
}
|
||||
if (!emac_task_hdl) {
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
goto _exit;
|
||||
@ -1223,21 +1225,20 @@ esp_err_t esp_eth_deinit(void)
|
||||
periph_module_disable(PERIPH_EMAC_MODULE);
|
||||
emac_config.emac_status = EMAC_RUNTIME_NOT_INIT;
|
||||
|
||||
/* free memory that dynamically allocted */
|
||||
for (int i = 0; i < DMA_RX_BUF_NUM; i++) {
|
||||
free(emac_dma_rx_chain_buf[i]);
|
||||
/* free memory that dynamically allocated */
|
||||
free(emac_dma_rx_chain_buf);
|
||||
free(emac_dma_tx_chain_buf);
|
||||
emac_dma_rx_chain_buf = NULL;
|
||||
emac_dma_tx_chain_buf = NULL;
|
||||
for (i = 0; i < DMA_RX_BUF_NUM; i++) {
|
||||
free(emac_dma_rx_buf[i]);
|
||||
emac_dma_rx_chain_buf[i] = NULL;
|
||||
emac_dma_rx_buf[i] = NULL;
|
||||
}
|
||||
for (int i = 0; i < DMA_TX_BUF_NUM; i++) {
|
||||
free(emac_dma_tx_chain_buf[i]);
|
||||
for (i = 0; i < DMA_TX_BUF_NUM; i++) {
|
||||
free(emac_dma_tx_buf[i]);
|
||||
emac_dma_tx_chain_buf[i] = NULL;
|
||||
emac_dma_tx_buf[i] = NULL;
|
||||
}
|
||||
ret = ESP_OK;
|
||||
|
||||
esp_intr_free(eth_intr_handle);
|
||||
_exit:
|
||||
return ret;
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ void phy_rmii_configure_data_interface_pins(void)
|
||||
{
|
||||
// CRS_DRV to GPIO27
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV);
|
||||
|
||||
// TXD0 to GPIO19
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
|
||||
// TX_EN to GPIO21
|
||||
@ -71,7 +70,7 @@ bool phy_mii_check_link_status(void)
|
||||
|
||||
bool phy_mii_get_partner_pause_enable(void)
|
||||
{
|
||||
if((esp_eth_smi_read(MII_PHY_LINK_PARTNER_ABILITY_REG) & MII_PARTNER_PAUSE)) {
|
||||
if ((esp_eth_smi_read(MII_PHY_LINK_PARTNER_ABILITY_REG) & MII_PARTNER_PAUSE)) {
|
||||
ESP_LOGD(TAG, "phy_mii_get_partner_pause_enable(TRUE)");
|
||||
return true;
|
||||
} else {
|
||||
|
116
components/ethernet/eth_phy/phy_ip101.c
Normal file
116
components/ethernet/eth_phy/phy_ip101.c
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "esp_log.h"
|
||||
#include "esp_eth.h"
|
||||
#include "eth_phy/phy_reg.h"
|
||||
#include "eth_phy/phy_ip101.h"
|
||||
|
||||
#define IP101_PHY_ID1 0x243
|
||||
#define IP101_PHY_ID2 0xc54
|
||||
#define IP101_PHY_ID2_MASK 0xFFF0
|
||||
|
||||
#define PHY_STATUS_REG (0x1e)
|
||||
#define DUPLEX_STATUS BIT(2)
|
||||
#define SPEED_STATUS BIT(1)
|
||||
|
||||
static const char *TAG = "ip101";
|
||||
|
||||
void phy_ip101_check_phy_init(void)
|
||||
{
|
||||
phy_ip101_dump_registers();
|
||||
esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0);
|
||||
}
|
||||
|
||||
eth_speed_mode_t phy_ip101_get_speed_mode(void)
|
||||
{
|
||||
if ((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS) == SPEED_STATUS) {
|
||||
ESP_LOGD(TAG, "phy_ip101_get_speed_mode(100)");
|
||||
return ETH_SPEED_MODE_100M;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "phy_ip101_get_speed_mode(10)");
|
||||
return ETH_SPEED_MODE_10M;
|
||||
}
|
||||
}
|
||||
|
||||
eth_duplex_mode_t phy_ip101_get_duplex_mode(void)
|
||||
{
|
||||
if ((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS) == DUPLEX_STATUS) {
|
||||
ESP_LOGD(TAG, "phy_ip101_get_duplex_mode(FULL)");
|
||||
return ETH_MODE_FULLDUPLEX;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "phy_ip101_get_duplex_mode(HALF)");
|
||||
return ETH_MODE_HALFDUPLEX;
|
||||
}
|
||||
}
|
||||
|
||||
void phy_ip101_power_enable(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
|
||||
data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION;
|
||||
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data);
|
||||
// TODO: only do this if config.flow_ctrl_enable == true
|
||||
phy_mii_enable_flow_ctrl();
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t phy_ip101_init(void)
|
||||
{
|
||||
esp_err_t res1, res2;
|
||||
ESP_LOGD(TAG, "phy_ip101_init()");
|
||||
phy_ip101_dump_registers();
|
||||
do {
|
||||
// Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically
|
||||
res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, IP101_PHY_ID1, UINT16_MAX, 1000);
|
||||
res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, IP101_PHY_ID2, IP101_PHY_ID2_MASK, 1000);
|
||||
} while (res1 != ESP_OK || res2 != ESP_OK);
|
||||
ets_delay_us(300);
|
||||
// TODO: only do this if config.flow_ctrl_enable == true
|
||||
phy_mii_enable_flow_ctrl();
|
||||
if (res1 == ESP_OK && res2 == ESP_OK) {
|
||||
return ESP_OK;
|
||||
} else {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
const eth_config_t phy_ip101_default_ethernet_config = {
|
||||
.phy_addr = 0x1,
|
||||
.mac_mode = ETH_MODE_RMII,
|
||||
.clock_mode = ETH_CLOCK_GPIO0_OUT,
|
||||
.flow_ctrl_enable = true,
|
||||
.phy_init = phy_ip101_init,
|
||||
.phy_check_init = phy_ip101_check_phy_init,
|
||||
.phy_check_link = phy_mii_check_link_status,
|
||||
.phy_get_speed_mode = phy_ip101_get_speed_mode,
|
||||
.phy_get_duplex_mode = phy_ip101_get_duplex_mode,
|
||||
.phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable,
|
||||
.phy_power_enable = phy_ip101_power_enable,
|
||||
};
|
||||
|
||||
void phy_ip101_dump_registers()
|
||||
{
|
||||
ESP_LOGD(TAG, "IP101 Registers:");
|
||||
ESP_LOGD(TAG, "BCR 0x%04x", esp_eth_smi_read(0x0));
|
||||
ESP_LOGD(TAG, "BSR 0x%04x", esp_eth_smi_read(0x1));
|
||||
ESP_LOGD(TAG, "PHY1 0x%04x", esp_eth_smi_read(0x2));
|
||||
ESP_LOGD(TAG, "PHY2 0x%04x", esp_eth_smi_read(0x3));
|
||||
ESP_LOGD(TAG, "ANAR 0x%04x", esp_eth_smi_read(0x4));
|
||||
ESP_LOGD(TAG, "ANLPAR 0x%04x", esp_eth_smi_read(0x5));
|
||||
ESP_LOGD(TAG, "ANER 0x%04x", esp_eth_smi_read(0x6));
|
||||
ESP_LOGD(TAG, "PSCR 0x%04x", esp_eth_smi_read(0x16));
|
||||
ESP_LOGD(TAG, "ISR 0x%04x", esp_eth_smi_read(0x17));
|
||||
ESP_LOGD(TAG, "ICR 0x%04x", esp_eth_smi_read(0x18));
|
||||
ESP_LOGD(TAG, "CSSR 0x%04x", esp_eth_smi_read(0x30));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user