diff --git a/.gitignore b/.gitignore index 25a5a30910..82f7fd3f2b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,15 +15,19 @@ GPATH .#* \#*# +# eclipse setting +.settings + # Example project files -examples/*/sdkconfig -examples/*/sdkconfig.old -examples/*/build +examples/*/*/sdkconfig +examples/*/*/sdkconfig.old +examples/*/*/build #Doc build artifacts docs/_build/ docs/doxygen-warning-log.txt docs/xml/ +docs/man/ # Unit test app files tools/unit-test-app/sdkconfig diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8cb5c8bcac..96bc56e3e6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -31,6 +31,7 @@ build_template_app: SDK_PATH: "$CI_PROJECT_DIR" IDF_PATH: "$CI_PROJECT_DIR" GIT_STRATEGY: clone + BATCH_BUILD: "1" script: - git clone https://github.com/espressif/esp-idf-template.git @@ -39,13 +40,11 @@ build_template_app: # using on esp-idf. If it doesn't exist then just stick to the default # branch - git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..." - - make defconfig # Test debug build (default) - make all V=1 # Now test release build - make clean - sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig - - make defconfig - make all V=1 # Check if there are any stray printf/ets_printf references in WiFi libs - cd ../components/esp32/lib @@ -63,6 +62,8 @@ build_template_app: SDK_PATH: "$CI_PROJECT_DIR" IDF_PATH: "$CI_PROJECT_DIR" GIT_STRATEGY: clone + BATCH_BUILD: "1" + build_ssc: <<: *build_template @@ -79,6 +80,15 @@ build_ssc: - chmod +x gen_misc_ng.sh - ./gen_misc_ng.sh +build_at: + <<: *build_template + script: + - git clone $GITLAB_SSH_SERVER/application/esp-at.git + - cd esp-at + - git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-at default branch..." + - make defconfig + - make + build_esp_idf_tests: <<: *build_template artifacts: @@ -87,13 +97,15 @@ build_esp_idf_tests: - ./tools/unit-test-app/build/*.elf - ./tools/unit-test-app/build/*.map - ./tools/unit-test-app/build/bootloader/*.bin + - ./components/idf_test/unit_test/TestCaseAll.yml + - ./components/idf_test/unit_test/CIConfigs/*.yml expire_in: 6 mos script: - cd tools/unit-test-app - git checkout ${CI_BUILD_REF_NAME} || echo "Using default branch..." - - make defconfig - make TESTS_ALL=1 + - python UnitTestParser.py build_examples: <<: *build_template @@ -122,6 +134,7 @@ build_docs: - doxygen # If not building master branch, and there are Doxygen warnings, print them and bail out - test "${CI_BUILD_REF_NAME}" = "master" || test $(cat doxygen-warning-log.txt | wc -l) -eq 0 || ( echo "Doxygen pass had some warnings:" && cat doxygen-warning-log.txt && false ) + - make gh-linkcheck - make html artifacts: paths: @@ -160,6 +173,7 @@ test_report: LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF" TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test" REPORT_PATH: "$CI_PROJECT_DIR/CI_Test_Report" + MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/tools/unit-test-app/ModuleDefinition.yml" artifacts: when: always paths: @@ -181,7 +195,7 @@ test_report: - cd auto_test_script # generate report - TEST_RESULT=Pass - - python CITestReport.py -l $LOG_PATH -t $TEST_CASE_FILE_PATH -p $REPORT_PATH -r $RESULT_PATH -a $ARTIFACTS_PATH || TEST_RESULT=Fail + - python CITestReport.py -l $LOG_PATH -t $TEST_CASE_FILE_PATH -p $REPORT_PATH -r $RESULT_PATH -a $ARTIFACTS_PATH -m $MODULE_UPDATE_FILE || TEST_RESULT=Fail # commit to CI-test-result project - git clone $GITLAB_SSH_SERVER/qa/CI-test-result.git - rm -rf CI-test-result/RawData/$RESULT_PATH @@ -202,6 +216,7 @@ push_master_to_github: stage: deploy only: - master + - /^release\/v.*$/ tags: - deploy when: on_success @@ -225,6 +240,7 @@ deploy_docs: stage: deploy only: - master + - /^release\/v.*$/ - triggers tags: - deploy @@ -243,6 +259,26 @@ deploy_docs: - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH - ssh $DOCS_SERVER -x "cd $DOCS_PATH && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" +check_doc_links: + stage: test + image: espressif/esp32-ci-env + tags: + - check_doc_links + only: + # can only be triggered + - triggers + script: + # must be triggered with CHECK_LINKS=Yes, otherwise exit without test + - test $CHECK_LINKS = "Yes" || exit 0 + # can only run on master branch (otherwise the commit is not on Github yet) + - test "${CI_BUILD_REF_NAME}" = "master" || exit 0 + - cd docs + - make linkcheck + artifacts: + paths: + - docs/_build/linkcheck + expire_in: 1 mos + # AUTO GENERATED PART START, DO NOT MODIFY CONTENT BELOW # template for test jobs @@ -255,14 +291,14 @@ deploy_docs: allow_failure: true variables: - # LOCAL_ENV_CONFIG_PATH: define in template and jobs can overwrite if required - LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF + LOCAL_ENV_CONFIG_PATH: $CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/ESP32_IDF BIN_PATH: "$CI_PROJECT_DIR/SSC/ssc_bin/SSC" APP_NAME: "ssc" LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF" # append test level folder to TEST_CASE_FILE_PATH in before_script of test job TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/integration_test" # jobs MUST set CONFIG_FILE in before_script, and overwrite the variables above if necessary + MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/components/idf_test/unit_test/ModuleDefinition.yml" artifacts: when: always @@ -280,11 +316,13 @@ deploy_docs: - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + # clone local test env configs + - git clone $GITLAB_SSH_SERVER/qa/ci-test-runner-configs.git # clone test bench - git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git - cd auto_test_script # run test - - python CIRunner.py -l $LOG_PATH -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH bin_path $APP_NAME $BIN_PATH + - python CIRunner.py -l $LOG_PATH -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE bin_path $APP_NAME $BIN_PATH # template for overnight test jobs @@ -305,11 +343,13 @@ deploy_docs: - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + # clone local test env configs + - git clone $GITLAB_SSH_SERVER/qa/ci-test-runner-configs.git # clone test bench - git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git - cd auto_test_script # run test - - python CIRunner.py -l $LOG_PATH -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH bin_path $APP_NAME $BIN_PATH + - python CIRunner.py -l $LOG_PATH -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE bin_path $APP_NAME $BIN_PATH # template for unit test jobs .unit_test_template: &unit_test_template @@ -318,12 +358,15 @@ deploy_docs: stage: unit_test variables: - # jobs MUST set CONFIG_FILE in before_script, and overwrite the variables above if necessary - LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF + LOCAL_ENV_CONFIG_PATH: $CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/ESP32_IDF BIN_PATH: "$CI_PROJECT_DIR/tools/unit-test-app/build/" LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF" APP_NAME: "ut" TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/unit_test" + MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/tools/unit-test-app/ModuleDefinition.yml" + + dependencies: + - build_esp_idf_tests UT_Function_SYS_01: <<: *unit_test_template @@ -333,6 +376,14 @@ UT_Function_SYS_01: before_script: - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/UT_Function_SYS_01.yml +UT_Function_SYS_02: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/UT_Function_SYS_02.yml + IT_Function_SYS_01: <<: *test_template tags: diff --git a/.gitmodules b/.gitmodules index 9cba0ec5ef..6a6af0e9d5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/espressif/esp32-wifi-lib.git [submodule "components/esptool_py/esptool"] path = components/esptool_py/esptool - url = https://github.com/themadinventor/esptool.git + url = https://github.com/espressif/esptool.git [submodule "components/bt/lib"] path = components/bt/lib url = https://github.com/espressif/esp32-bt-lib.git diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 5810d06b98..df40705044 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -21,7 +21,7 @@ Before sending us a Pull Request, please consider this list of points: * Is the code adequately commented for people to understand how it is structured? -* Is there documentation or examples that go with code contributions? `There are additional suggestions for writing good examples in the examples README `_. +* Is there documentation or examples that go with code contributions? There are additional suggestions for writing good examples in :idf:`examples` readme. * Are comments and documentation written in clear English, with no spelling or grammar errors? diff --git a/README.md b/README.md index 64fe3ed365..312817b3a5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![alt text](https://readthedocs.org/projects/docs/badge/?version=latest "Documentation Status")](http://esp-idf.readthedocs.io/en/latest/?badge=latest) -ESP-IDF is the official development framework for the `ESP32 `_ chip. +ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview>) chip. # Developing With the ESP-IDF @@ -24,6 +24,16 @@ Once you've found the project you want to work with, change to its directory and `make menuconfig` +* Opens a text-based configuration menu for the project. +* Use up & down arrow keys to navigate the menu. +* Use Enter key to go into a submenu, Escape key to go out or to exit. +* Type `?` to see a help screen. Enter key exits the help screen. +* Use Space key, or `Y` and `N` keys to enable (Yes) and disable (No) configuration items with checkboxes "`[*]`" +* Pressing `?` while highlighting a configuration item displays help about that item. +* Type `/` to search the configuration items. + +Once done configuring, press Escape multiple times to exit and say "Yes" to save the new configuration when prompted. + ## Compiling the Project `make all` @@ -59,7 +69,7 @@ After the initial flash, you may just want to build and flash just your app, not `make app-flash` will automatically rebuild the app if it needs it. -(There's no downside to reflashing the bootloader and partition table each time, if they haven't changed.) +(In normal development there's no downside to reflashing the bootloader and partition table each time, if they haven't changed.) ## Parallel Builds diff --git a/add_path.sh b/add_path.sh index 6b69f8d44f..1c0b0ed0ed 100644 --- a/add_path.sh +++ b/add_path.sh @@ -9,7 +9,7 @@ if [ -z ${IDF_PATH} ]; then echo "IDF_PATH must be set before including this script." else - IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool:${IDF_PATH}/components/partition_table/" + IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool:${IDF_PATH}/components/espcoredump:${IDF_PATH}/components/partition_table/" export PATH="${PATH}:${IDF_ADD_PATHS_EXTRAS}" echo "Added to PATH: ${IDF_ADD_PATHS_EXTRAS}" fi diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index 439117b596..c702a203e2 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -27,6 +27,7 @@ #include "esp_spi_flash.h" #include "esp_image_format.h" #include "esp_secure_boot.h" +#include "esp_flash_encrypt.h" #include "sdkconfig.h" #include "esp_ota_ops.h" @@ -44,6 +45,10 @@ typedef struct ota_ops_entry_ { esp_partition_t part; uint32_t erased_size; uint32_t wrote_size; +#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED + uint8_t partial_bytes; + uint8_t partial_data[16]; +#endif LIST_ENTRY(ota_ops_entry_) entries; } ota_ops_entry_t; @@ -106,6 +111,7 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size) { + const uint8_t *data_bytes = (const uint8_t *)data; esp_err_t ret; ota_ops_entry_t *it; @@ -119,7 +125,47 @@ 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"); - ret = esp_partition_write(&it->part, it->wrote_size, data, size); + + if(it->wrote_size == 0 && size > 0 && data_bytes[0] != 0xE9) { + ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x", data_bytes[0]); + return ESP_ERR_OTA_VALIDATE_FAILED; + } + +#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED + if (esp_flash_encryption_enabled()) { + /* Can only write 16 byte blocks to flash, so need to cache anything else */ + size_t copy_len; + + /* check if we have partially written data from earlier */ + if (it->partial_bytes != 0) { + copy_len = OTA_MIN(16 - it->partial_bytes, size); + memcpy(it->partial_data + it->partial_bytes, data_bytes, copy_len); + it->partial_bytes += copy_len; + if (it->partial_bytes != 16) { + return ESP_OK; /* nothing to write yet, just filling buffer */ + } + /* write 16 byte to partition */ + ret = esp_partition_write(&it->part, it->wrote_size, it->partial_data, 16); + if (ret != ESP_OK) { + return ret; + } + it->partial_bytes = 0; + memset(it->partial_data, 0xFF, 16); + it->wrote_size += 16; + data_bytes += copy_len; + size -= copy_len; + } + + /* check if we need to save trailing data that we're about to write */ + it->partial_bytes = size % 16; + if (it->partial_bytes != 0) { + size -= it->partial_bytes; + memcpy(it->partial_data, data_bytes + size, it->partial_bytes); + } + } +#endif + + ret = esp_partition_write(&it->part, it->wrote_size, data_bytes, size); if(ret == ESP_OK){ it->wrote_size += size; } @@ -135,26 +181,11 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size) esp_err_t esp_ota_end(esp_ota_handle_t handle) { ota_ops_entry_t *it; + size_t image_size; + esp_err_t ret = ESP_OK; + for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { if (it->handle == handle) { - // an ota handle need to be ended after erased and wrote data in it - if ((it->erased_size == 0) || (it->wrote_size == 0)) { - return ESP_ERR_INVALID_ARG; - } - -#ifdef CONFIG_SECUREBOOTLOADER - esp_err_t ret; - size_t image_size; - if (esp_image_basic_verify(it->part.address, &image_size) != ESP_OK) { - return ESP_ERR_OTA_VALIDATE_FAILED; - } - ret = esp_secure_boot_verify_signature(it->part.address, image_size); - if (ret != ESP_OK) { - return ESP_ERR_OTA_VALIDATE_FAILED; - } -#endif - - LIST_REMOVE(it, entries); break; } } @@ -163,8 +194,44 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle) return ESP_ERR_NOT_FOUND; } + /* 'it' holds the ota_ops_entry_t for 'handle' */ + + // esp_ota_end() is only valid if some data was written to this handle + if ((it->erased_size == 0) || (it->wrote_size == 0)) { + ret = ESP_ERR_INVALID_ARG; + goto cleanup; + } + +#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED + if (it->partial_bytes > 0 && esp_flash_encryption_enabled()) { + /* Write out last 16 bytes, if necessary */ + ret = esp_partition_write(&it->part, it->wrote_size, it->partial_data, 16); + if (ret != ESP_OK) { + ret = ESP_ERR_INVALID_STATE; + goto cleanup; + } + it->wrote_size += 16; + it->partial_bytes = 0; + } +#endif + + if (esp_image_basic_verify(it->part.address, true, &image_size) != ESP_OK) { + ret = ESP_ERR_OTA_VALIDATE_FAILED; + goto cleanup; + } + +#ifdef CONFIG_SECURE_BOOT_ENABLED + ret = esp_secure_boot_verify_signature(it->part.address, image_size); + if (ret != ESP_OK) { + ret = ESP_ERR_OTA_VALIDATE_FAILED; + goto cleanup; + } +#endif + + cleanup: + LIST_REMOVE(it, entries); free(it); - return ESP_OK; + return ret; } static uint32_t ota_select_crc(const ota_select *s) @@ -271,11 +338,9 @@ static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype) } return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition); - } else if (s_ota_select[0].ota_seq == 0xFFFFFFFF && s_ota_select[1].ota_seq == 0xFFFFFFFF) { - return rewrite_ota_seq(SUB_TYPE_ID(subtype) + 1, 0, find_partition); - } else { - return ESP_ERR_OTA_SELECT_INFO_INVALID; + /* Both OTA slots are invalid, probably because unformatted... */ + return rewrite_ota_seq(SUB_TYPE_ID(subtype) + 1, 0, find_partition); } } else { @@ -285,17 +350,18 @@ static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype) esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition) { + size_t image_size; const esp_partition_t *find_partition = NULL; if (partition == NULL) { return ESP_ERR_INVALID_ARG; } -#ifdef CONFIG_SECUREBOOTLOADER - size_t image_size; - if (esp_image_basic_verify(partition->address, &image_size) != ESP_OK) { + if (esp_image_basic_verify(partition->address, true, &image_size) != ESP_OK) { return ESP_ERR_OTA_VALIDATE_FAILED; } - ret = esp_secure_boot_verify_signature(partition->address, image_size); + +#ifdef CONFIG_SECURE_BOOT_ENABLED + esp_err_t ret = esp_secure_boot_verify_signature(partition->address, image_size); if (ret != ESP_OK) { return ESP_ERR_OTA_VALIDATE_FAILED; } @@ -349,33 +415,34 @@ const esp_partition_t *esp_ota_get_boot_partition(void) } ota_app_count = get_ota_partition_count(); - ESP_LOGD(TAG, "found ota bin max = %d", ota_app_count); + ESP_LOGD(TAG, "found ota app max = %d", ota_app_count); + if (s_ota_select[0].ota_seq == 0xFFFFFFFF && s_ota_select[1].ota_seq == 0xFFFFFFFF) { - ESP_LOGD(TAG, "finding factory bin......"); + ESP_LOGD(TAG, "finding factory app......"); return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); } else if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) { - ESP_LOGD(TAG, "finding ota_%d bin......", \ + ESP_LOGD(TAG, "finding ota_%d app......", \ ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count)); return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \ ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count), NULL); } else if (ota_select_valid(&s_ota_select[0])) { - ESP_LOGD(TAG, "finding ota_%d bin......", \ + ESP_LOGD(TAG, "finding ota_%d app......", \ ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count); return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \ ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count, NULL); } else if (ota_select_valid(&s_ota_select[1])) { - ESP_LOGD(TAG, "finding ota_%d bin......", \ + ESP_LOGD(TAG, "finding ota_%d app......", \ ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count); return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \ ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count, NULL); } else { - ESP_LOGE(TAG, "not found current bin"); - return NULL; + ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory"); + return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); } } diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index 846aa2b2cf..fe3307763f 100755 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -73,11 +73,16 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void* data, size_t size); /** * @brief Finish the update and validate written data * - * @param handle Handle obtained from esp_ota_begin + * @param handle Handle obtained from esp_ota_begin. * - * @return: - * - ESP_OK: if validate ota image pass - * - ESP_ERR_OTA_VALIDATE_FAILED: validate the ota image is invalid + * @note After calling esp_ota_end(), the handle is no longer valid and any memory associated with it is freed (regardless of result). + * + * @return: + * - ESP_OK: Newly written OTA app image is valid. + * - ESP_ERR_NOT_FOUND: OTA handle was not found. + * - ESP_ERR_INVALID_ARG: Handle was never written to. + * - ESP_ERR_OTA_VALIDATE_FAILED: OTA image is invalid (either not a valid app image, or - if secure boot is enabled - signature failed to verify.) + * - ESP_ERR_INVALID_STATE: If flash encryption is enabled, this result indicates an internal error writing the final encrypted bytes to flash. */ esp_err_t esp_ota_end(esp_ota_handle_t handle); diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 798fcf0b23..ac4d1d14b9 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -35,16 +35,16 @@ endmenu menu "Security features" config SECURE_BOOT_ENABLED - bool "Enable secure boot in bootloader" + bool "Enable secure boot in bootloader (READ DOCS FIRST)" default N help Build a bootloader which enables secure boot on first boot. - Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition table or boot an app if the data has a verified digital signature. + Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition table or boot an app if the data has a verified digital signature. There are implications for reflashing updated apps once secure boot is enabled. When enabling secure boot, JTAG and ROM BASIC Interpreter are permanently disabled by default. - See docs/security/secure-boot.rst for details. + Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling. choice SECURE_BOOTLOADER_MODE bool "Secure bootloader mode" @@ -108,7 +108,7 @@ config SECURE_BOOT_VERIFICATION_KEY PEM formatted private key using the espsecure.py extract_public_key command. - See docs/security/secure-boot.rst for details. + Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling. config SECURE_BOOT_INSECURE bool "Allow potentially insecure options" @@ -119,16 +119,18 @@ config SECURE_BOOT_INSECURE Only enable these options if you are very sure. - Refer to docs/security/secure-boot.rst and docs/security/flash-encryption.rst for details. + Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling. config FLASH_ENCRYPTION_ENABLED - bool "Enable flash encryption on boot" + bool "Enable flash encryption on boot (READ DOCS FIRST)" default N help If this option is set, flash contents will be encrypted by the bootloader on first boot. - Note: After first boot, the system will be permanently encrypted. - See docs/securityflash-encryption.rst for details. + Note: After first boot, the system will be permanently encrypted. Re-flashing an encrypted + system is complicated and not always possible. + + Read http://esp-idf.readthedocs.io/en/latest/security/flash-encryption.html before enabling. config FLASH_ENCRYPTION_INSECURE bool "Allow potentially insecure options" diff --git a/components/bootloader/src/main/Makefile.projbuild b/components/bootloader/src/main/Makefile.projbuild new file mode 100644 index 0000000000..c368c68416 --- /dev/null +++ b/components/bootloader/src/main/Makefile.projbuild @@ -0,0 +1,4 @@ +# Submodules normally added in component.mk, but fully qualified +# paths can be added at this level (we need binary librtc to be +# available to link bootloader). +COMPONENT_SUBMODULES += $(IDF_PATH)/components/esp32/lib diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index a374c4306d..43066aa3d7 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -323,12 +323,15 @@ void bootloader_main() } else { if(ota_select_valid(&sa) && ota_select_valid(&sb)) { load_part_pos = bs.ota[(((sa.ota_seq > sb.ota_seq)?sa.ota_seq:sb.ota_seq) - 1)%bs.app_count]; - }else if(ota_select_valid(&sa)) { + } else if(ota_select_valid(&sa)) { load_part_pos = bs.ota[(sa.ota_seq - 1) % bs.app_count]; - }else if(ota_select_valid(&sb)) { + } else if(ota_select_valid(&sb)) { load_part_pos = bs.ota[(sb.ota_seq - 1) % bs.app_count]; - }else { - ESP_LOGE(TAG, "ota data partition info error"); + } else if (bs.factory.offset != 0) { + ESP_LOGE(TAG, "ota data partition invalid, falling back to factory"); + load_part_pos = bs.factory; + } else { + ESP_LOGE(TAG, "ota data partition invalid and no factory, can't boot"); return; } } diff --git a/components/bootloader/src/main/component.mk b/components/bootloader/src/main/component.mk index 73cd9287df..12fdf8efa0 100644 --- a/components/bootloader/src/main/component.mk +++ b/components/bootloader/src/main/component.mk @@ -14,10 +14,10 @@ COMPONENT_ADD_LDFLAGS := -L $(COMPONENT_PATH) -lmain $(addprefix -T ,$(LINKER_SC COMPONENT_ADD_LINKER_DEPS := $(LINKER_SCRIPTS) -ifdef IS_BOOTLOADER_BUILD # following lines are a workaround to link librtc into the # bootloader, until clock setting code is in a source-based esp-idf # component. See also rtc_printf() in bootloader_start.c -COMPONENT_ADD_LDFLAGS += -L $(IDF_PATH)/components/esp32/lib/ -lrtc +# +# See also matching COMPONENT_SUBMODULES line in Makefile.projbuild +COMPONENT_ADD_LDFLAGS += -L $(IDF_PATH)/components/esp32/lib/ -lrtc_clk -lrtc COMPONENT_EXTRA_INCLUDES += $(IDF_PATH)/components/esp32/ -endif diff --git a/components/bootloader_support/include/esp_flash_encrypt.h b/components/bootloader_support/include/esp_flash_encrypt.h index 015dea030a..09e365724e 100644 --- a/components/bootloader_support/include/esp_flash_encrypt.h +++ b/components/bootloader_support/include/esp_flash_encrypt.h @@ -15,14 +15,17 @@ #define __ESP32_FLASH_ENCRYPT_H #include -#include +#include "esp_attr.h" +#include "esp_err.h" #include "esp_spi_flash.h" #include "soc/efuse_reg.h" -/* Support functions for flash encryption features. - - Can be compiled as part of app or bootloader code. -*/ +/** + * @file esp_partition.h + * @brief Support functions for flash encryption features + * + * Can be compiled as part of app or bootloader code. + */ /** @brief Is flash encryption currently enabled in hardware? * @@ -30,9 +33,17 @@ * * @return true if flash encryption is enabled. */ -static inline bool esp_flash_encryption_enabled(void) { +static inline IRAM_ATTR bool esp_flash_encryption_enabled(void) { uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_RD_FLASH_CRYPT_CNT); - return __builtin_parity(flash_crypt_cnt) == 1; + /* __builtin_parity is in flash, so we calculate parity inline */ + bool enabled = false; + while(flash_crypt_cnt) { + if (flash_crypt_cnt & 1) { + enabled = !enabled; + } + flash_crypt_cnt >>= 1; + } + return enabled; } /* @brief Update on-device flash encryption diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 405da732b3..da77b1dc28 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -16,6 +16,7 @@ #include #include #include /* including in bootloader for error values */ +#include #ifndef BOOTLOADER_BUILD /* Normal app version maps to esp_spi_flash.h operations... @@ -48,7 +49,11 @@ void bootloader_munmap(const void *mapping) esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size, bool allow_decrypt) { - return spi_flash_read(src, dest, size); + if (allow_decrypt && esp_flash_encryption_enabled()) { + return spi_flash_read_encrypted(src, dest, size); + } else { + return spi_flash_read(src, dest, size); + } } esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted) diff --git a/components/bootloader_support/src/bootloader_random.c b/components/bootloader_support/src/bootloader_random.c index b58ebe941d..5a00d0cf5a 100644 --- a/components/bootloader_support/src/bootloader_random.c +++ b/components/bootloader_support/src/bootloader_random.c @@ -135,4 +135,8 @@ void bootloader_random_disable(void) /* Reset i2s peripheral */ SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + + /* Disable pull supply voltage to SAR ADC */ + CLEAR_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC); + SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 0, RTC_CNTL_DTEST_RTC_S); } diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c index 8b9ca60cd1..8ba068d03b 100644 --- a/components/bootloader_support/src/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encrypt.c @@ -285,6 +285,9 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit } else { should_encrypt = false; } + } else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) { + /* check if we have ota data partition and the partition should be encrypted unconditionally */ + should_encrypt = true; } if (!should_encrypt) { diff --git a/components/bt/bluedroid/api/esp_bt_main.c b/components/bt/bluedroid/api/esp_bt_main.c index c9fe4fc060..5f7265e99c 100644 --- a/components/bt/bluedroid/api/esp_bt_main.c +++ b/components/bt/bluedroid/api/esp_bt_main.c @@ -16,6 +16,7 @@ #include "esp_bt_main.h" #include "btc_task.h" #include "btc_main.h" +#include "bt.h" #include "future.h" static bool esp_already_enable = false; @@ -103,6 +104,11 @@ esp_err_t esp_bluedroid_init(void) btc_msg_t msg; future_t **future_p; + if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { + LOG_ERROR("%s conroller not init\n", __func__); + return ESP_ERR_INVALID_STATE; + } + if (esp_already_init) { LOG_ERROR("%s already init\n", __func__); return ESP_ERR_INVALID_STATE; diff --git a/components/bt/bluedroid/api/esp_gap_ble_api.c b/components/bt/bluedroid/api/esp_gap_ble_api.c index 56bedc4242..2807281aed 100644 --- a/components/bt/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/bluedroid/api/esp_gap_ble_api.c @@ -252,3 +252,50 @@ uint8_t *esp_ble_resolve_adv_data( uint8_t *adv_data, uint8_t type, uint8_t *len return (BTM_CheckAdvData( adv_data, type, length)); } +esp_err_t esp_ble_gap_config_adv_data_raw(uint8_t *raw_data, uint32_t raw_data_len) +{ + btc_msg_t msg; + btc_ble_gap_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (raw_data == NULL + || (raw_data_len <= 0 || raw_data_len > ESP_BLE_ADV_DATA_LEN_MAX)) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW; + arg.cfg_adv_data_raw.raw_adv = raw_data; + arg.cfg_adv_data_raw.raw_adv_len = raw_data_len; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), btc_gap_ble_arg_deep_copy) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); + +} + +esp_err_t esp_ble_gap_config_scan_rsp_data_raw(uint8_t *raw_data, uint32_t raw_data_len) +{ + btc_msg_t msg; + btc_ble_gap_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (raw_data == NULL + || (raw_data_len <= 0 || raw_data_len > ESP_BLE_SCAN_RSP_DATA_LEN_MAX)) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW; + arg.cfg_scan_rsp_data_raw.raw_scan_rsp = raw_data; + arg.cfg_scan_rsp_data_raw.raw_scan_rsp_len = raw_data_len; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), btc_gap_ble_arg_deep_copy) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); + +} diff --git a/components/bt/bluedroid/api/include/esp_gap_ble_api.h b/components/bt/bluedroid/api/include/esp_gap_ble_api.h index 1d27edb881..64aff1fb1a 100644 --- a/components/bt/bluedroid/api/include/esp_gap_ble_api.h +++ b/components/bt/bluedroid/api/include/esp_gap_ble_api.h @@ -44,6 +44,8 @@ typedef enum { ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT, /*!< When scan response data set complete, the event comes */ ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT, /*!< When scan parameters set complete, the event comes */ ESP_GAP_BLE_SCAN_RESULT_EVT, /*!< When one scan result ready, the event comes each time */ + ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT, /*!< When raw advertising data set complete, the event comes */ + ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT, /*!< When raw advertising data set complete, the event comes */ } esp_gap_ble_cb_event_t; /// Advertising data maximum length @@ -93,7 +95,7 @@ typedef enum { typedef enum { ADV_CHNL_37 = 0x01, ADV_CHNL_38 = 0x02, - ADV_CHNL_39 = 0x03, + ADV_CHNL_39 = 0x04, ADV_CHNL_ALL = 0x07, } esp_ble_adv_channel_t; @@ -270,6 +272,18 @@ typedef union { int flag; /*!< Advertising data flag bit */ int num_resps; /*!< Scan result number */ } scan_rst; /*!< Event parameter of ESP_GAP_BLE_SCAN_RESULT_EVT */ + /** + * @brief ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT + */ + struct ble_adv_data_raw_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set raw advertising data operation success status */ + } adv_data_raw_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT + */ + struct ble_scan_rsp_data_raw_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set raw advertising data operation success status */ + } scan_rsp_data_raw_cmpl; /*!< Event parameter of ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT */ } esp_ble_gap_cb_param_t; /** @@ -448,6 +462,33 @@ esp_err_t esp_ble_gap_set_device_name(const char *name); */ uint8_t *esp_ble_resolve_adv_data(uint8_t *adv_data, uint8_t type, uint8_t *length); +/** + * @brief This function is called to set raw advertising data. User need to fill + * ADV data by self. + * + * @param[in] raw_data : raw advertising data + * @param[in] raw_data_len : raw advertising data length , less than 31 bytes + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_config_adv_data_raw(uint8_t *raw_data, uint32_t raw_data_len); + +/** + * @brief This function is called to set raw scan response data. User need to fill + * scan response data by self. + * + * @param[in] raw_data : raw scan response data + * @param[in] raw_data_len : raw scan response data length , less than 31 bytes + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_config_scan_rsp_data_raw(uint8_t *raw_data, uint32_t raw_data_len); + #ifdef __cplusplus } #endif diff --git a/components/bt/bluedroid/api/include/esp_gatts_api.h b/components/bt/bluedroid/api/include/esp_gatts_api.h index b18039ce79..777bbec3de 100644 --- a/components/bt/bluedroid/api/include/esp_gatts_api.h +++ b/components/bt/bluedroid/api/include/esp_gatts_api.h @@ -449,7 +449,8 @@ esp_err_t esp_ble_gatts_stop_service(uint16_t service_handle); * @param[in] attr_handle - attribute handle to indicate. * @param[in] value_len - indicate value length. * @param[in] value: value to indicate. - * @param[in] need_confirm - if this indication expects a confirmation or not. + * @param[in] need_confirm - Whether a confirmation is required. + * false sends a GATT notification, true sends a GATT indication. * * @return * - ESP_OK : success diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index 67af7f03bf..66eb55dac2 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -4608,6 +4608,30 @@ void bta_dm_ble_set_adv_config (tBTA_DM_MSG *p_data) } } +/******************************************************************************* +** +** Function bta_dm_ble_set_adv_config_raw +** +** Description This function set the customized ADV data configuration +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_adv_config_raw (tBTA_DM_MSG *p_data) +{ + tBTA_STATUS status = BTA_FAILURE; + + if (BTM_BleWriteAdvDataRaw(p_data->ble_set_adv_data_raw.p_raw_adv, + p_data->ble_set_adv_data_raw.raw_adv_len) == BTM_SUCCESS) { + status = BTA_SUCCESS; + } + + if (p_data->ble_set_adv_data_raw.p_adv_data_cback) { + (*p_data->ble_set_adv_data_raw.p_adv_data_cback)(status); + } +} + + /******************************************************************************* ** ** Function bta_dm_ble_set_scan_rsp @@ -4631,6 +4655,29 @@ void bta_dm_ble_set_scan_rsp (tBTA_DM_MSG *p_data) } } +/******************************************************************************* +** +** Function bta_dm_ble_set_scan_rsp_raw +** +** Description This function set the raw scan response data +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_scan_rsp_raw (tBTA_DM_MSG *p_data) +{ + tBTA_STATUS status = BTA_FAILURE; + + if (BTM_BleWriteScanRspRaw(p_data->ble_set_adv_data_raw.p_raw_adv, + p_data->ble_set_adv_data_raw.raw_adv_len) == BTM_SUCCESS) { + status = BTA_SUCCESS; + } + + if (p_data->ble_set_adv_data_raw.p_adv_data_cback) { + (*p_data->ble_set_adv_data_raw.p_adv_data_cback)(status); + } +} + /******************************************************************************* ** ** Function bta_dm_ble_set_data_length diff --git a/components/bt/bluedroid/bta/dm/bta_dm_api.c b/components/bt/bluedroid/bta/dm/bta_dm_api.c index 914bbfabc2..132d2ea8f7 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_api.c @@ -1077,6 +1077,35 @@ void BTA_DmBleSetAdvConfig (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_adv } } +/******************************************************************************* +** +** Function BTA_DmBleSetAdvConfigRaw +** +** Description This function is called to set raw Advertising data +** +** Parameters p_raw_adv : raw advertising data. +** raw_adv_len : raw advertising data length. +** p_adv_data_cback : set adv data complete callback. +** +** Returns None +** +*******************************************************************************/ +void BTA_DmBleSetAdvConfigRaw (UINT8 *p_raw_adv, UINT32 raw_adv_len, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback) +{ + tBTA_DM_API_SET_ADV_CONFIG_RAW *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_ADV_CONFIG_RAW *) + GKI_getbuf(sizeof(tBTA_DM_API_SET_ADV_CONFIG_RAW))) != NULL) { + p_msg->hdr.event = BTA_DM_API_BLE_SET_ADV_CONFIG_RAW_EVT; + p_msg->p_adv_data_cback = p_adv_data_cback; + p_msg->p_raw_adv = p_raw_adv; + p_msg->raw_adv_len = raw_adv_len; + + bta_sys_sendmsg(p_msg); + } +} + /******************************************************************************* ** ** Function BTA_DmBleSetScanRsp @@ -1104,6 +1133,35 @@ extern void BTA_DmBleSetScanRsp (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA * } } +/******************************************************************************* +** +** Function BTA_DmBleSetScanRspRaw +** +** Description This function is called to set raw scan response data +** +** Parameters p_raw_scan_rsp : raw scan_rspertising data. +** raw_scan_rsp_len : raw scan_rspertising data length. +** p_scan_rsp_data_cback : set scan_rsp data complete callback. +** +** Returns None +** +*******************************************************************************/ +void BTA_DmBleSetScanRspRaw (UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_len, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_scan_rsp_data_cback) +{ + tBTA_DM_API_SET_ADV_CONFIG_RAW *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_ADV_CONFIG_RAW *) + GKI_getbuf(sizeof(tBTA_DM_API_SET_ADV_CONFIG_RAW))) != NULL) { + p_msg->hdr.event = BTA_DM_API_BLE_SET_SCAN_RSP_RAW_EVT; + p_msg->p_adv_data_cback = p_scan_rsp_data_cback; + p_msg->p_raw_adv = p_raw_scan_rsp; + p_msg->raw_adv_len = raw_scan_rsp_len; + + bta_sys_sendmsg(p_msg); + } +} + /******************************************************************************* ** ** Function BTA_DmBleSetStorageParams diff --git a/components/bt/bluedroid/bta/dm/bta_dm_int.h b/components/bt/bluedroid/bta/dm/bta_dm_int.h index 80e0bea477..7475ad254e 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_int.h +++ b/components/bt/bluedroid/bta/dm/bta_dm_int.h @@ -109,7 +109,11 @@ enum { support setting the ble advertising param by the APP******/ BTA_DM_API_BLE_ADV_PARAM_All_EVT, BTA_DM_API_BLE_SET_ADV_CONFIG_EVT, + /* Add for set raw advertising data */ + BTA_DM_API_BLE_SET_ADV_CONFIG_RAW_EVT, BTA_DM_API_BLE_SET_SCAN_RSP_EVT, + /* Add for set raw scan response data */ + BTA_DM_API_BLE_SET_SCAN_RSP_RAW_EVT, BTA_DM_API_BLE_BROADCAST_EVT, BTA_DM_API_SET_DATA_LENGTH_EVT, @@ -545,6 +549,15 @@ typedef struct { tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback; } tBTA_DM_API_SET_ADV_CONFIG; +/* raw scan response and raw advertising data use + the same structure */ +typedef struct { + BT_HDR hdr; + UINT8 *p_raw_adv; + UINT32 raw_adv_len; + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback; +} tBTA_DM_API_SET_ADV_CONFIG_RAW; + typedef struct { BT_HDR hdr; UINT8 batch_scan_full_max; @@ -708,6 +721,7 @@ typedef union { tBTA_DM_API_BLE_ADV_PARAMS ble_set_adv_params; tBTA_DM_API_BLE_ADV_PARAMS_ALL ble_set_adv_params_all; tBTA_DM_API_SET_ADV_CONFIG ble_set_adv_data; + tBTA_DM_API_SET_ADV_CONFIG_RAW ble_set_adv_data_raw; #if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE tBTA_DM_API_SCAN_FILTER_PARAM_SETUP ble_scan_filt_param_setup; tBTA_DM_API_CFG_FILTER_COND ble_cfg_filter_cond; @@ -1093,9 +1107,11 @@ extern void bta_dm_ble_set_rand_address(tBTA_DM_MSG *p_data); extern void bta_dm_ble_stop_advertising(tBTA_DM_MSG *p_data); extern void bta_dm_ble_config_local_privacy (tBTA_DM_MSG *p_data); extern void bta_dm_ble_set_adv_params (tBTA_DM_MSG *p_data); -extern void bta_dm_ble_set_adv_params_all (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_adv_params_all(tBTA_DM_MSG *p_data); extern void bta_dm_ble_set_adv_config (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_adv_config_raw (tBTA_DM_MSG *p_data); extern void bta_dm_ble_set_scan_rsp (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_scan_rsp_raw (tBTA_DM_MSG *p_data); extern void bta_dm_ble_broadcast (tBTA_DM_MSG *p_data); extern void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data); diff --git a/components/bt/bluedroid/bta/dm/bta_dm_main.c b/components/bt/bluedroid/bta/dm/bta_dm_main.c index ea3f54618f..25c4978538 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_main.c @@ -47,86 +47,95 @@ typedef void (*tBTA_DM_ACTION)(tBTA_DM_MSG *p_data); const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { /* device manager local device API events */ - bta_dm_enable, /* 0 BTA_DM_API_ENABLE_EVT */ - bta_dm_disable, /* 1 BTA_DM_API_DISABLE_EVT */ - bta_dm_set_dev_name, /* 2 BTA_DM_API_SET_NAME_EVT */ - bta_dm_set_visibility, /* 3 BTA_DM_API_SET_VISIBILITY_EVT */ - bta_dm_acl_change, /* 8 BTA_DM_ACL_CHANGE_EVT */ - bta_dm_add_device, /* 9 BTA_DM_API_ADD_DEVICE_EVT */ - bta_dm_close_acl, /* 10 BTA_DM_API_ADD_DEVICE_EVT */ + bta_dm_enable, /* 0 BTA_DM_API_ENABLE_EVT */ + bta_dm_disable, /* 1 BTA_DM_API_DISABLE_EVT */ + bta_dm_set_dev_name, /* 2 BTA_DM_API_SET_NAME_EVT */ + bta_dm_set_visibility, /* 3 BTA_DM_API_SET_VISIBILITY_EVT */ + bta_dm_acl_change, /* 8 BTA_DM_ACL_CHANGE_EVT */ + bta_dm_add_device, /* 9 BTA_DM_API_ADD_DEVICE_EVT */ + bta_dm_close_acl, /* 10 BTA_DM_API_ADD_DEVICE_EVT */ /* security API events */ - bta_dm_bond, /* 11 BTA_DM_API_BOND_EVT */ - bta_dm_bond_cancel, /* 12 BTA_DM_API_BOND_CANCEL_EVT */ - bta_dm_pin_reply, /* 13 BTA_DM_API_PIN_REPLY_EVT */ + bta_dm_bond, /* 11 BTA_DM_API_BOND_EVT */ + bta_dm_bond_cancel, /* 12 BTA_DM_API_BOND_CANCEL_EVT */ + bta_dm_pin_reply, /* 13 BTA_DM_API_PIN_REPLY_EVT */ /* power manger events */ - bta_dm_pm_btm_status, /* 16 BTA_DM_PM_BTM_STATUS_EVT */ - bta_dm_pm_timer, /* 17 BTA_DM_PM_TIMER_EVT*/ + bta_dm_pm_btm_status, /* 16 BTA_DM_PM_BTM_STATUS_EVT */ + bta_dm_pm_timer, /* 17 BTA_DM_PM_TIMER_EVT*/ /* simple pairing events */ - bta_dm_confirm, /* 18 BTA_DM_API_CONFIRM_EVT */ + bta_dm_confirm, /* 18 BTA_DM_API_CONFIRM_EVT */ - bta_dm_set_encryption, /* BTA_DM_API_SET_ENCRYPTION_EVT */ + bta_dm_set_encryption, /* BTA_DM_API_SET_ENCRYPTION_EVT */ #if (BTM_OOB_INCLUDED == TRUE) - bta_dm_loc_oob, /* 20 BTA_DM_API_LOC_OOB_EVT */ - bta_dm_ci_io_req_act, /* 21 BTA_DM_CI_IO_REQ_EVT */ - bta_dm_ci_rmt_oob_act, /* 22 BTA_DM_CI_RMT_OOB_EVT */ + bta_dm_loc_oob, /* 20 BTA_DM_API_LOC_OOB_EVT */ + bta_dm_ci_io_req_act, /* 21 BTA_DM_CI_IO_REQ_EVT */ + bta_dm_ci_rmt_oob_act, /* 22 BTA_DM_CI_RMT_OOB_EVT */ #endif /* BTM_OOB_INCLUDED */ #if BLE_INCLUDED == TRUE - bta_dm_add_blekey, /* BTA_DM_API_ADD_BLEKEY_EVT */ - bta_dm_add_ble_device, /* BTA_DM_API_ADD_BLEDEVICE_EVT */ - bta_dm_ble_passkey_reply, /* BTA_DM_API_BLE_PASSKEY_REPLY_EVT */ - bta_dm_ble_confirm_reply, /* BTA_DM_API_BLE_CONFIRM_REPLY_EVT */ + bta_dm_add_blekey, /* BTA_DM_API_ADD_BLEKEY_EVT */ + bta_dm_add_ble_device, /* BTA_DM_API_ADD_BLEDEVICE_EVT */ + bta_dm_ble_passkey_reply, /* BTA_DM_API_BLE_PASSKEY_REPLY_EVT */ + bta_dm_ble_confirm_reply, /* BTA_DM_API_BLE_CONFIRM_REPLY_EVT */ bta_dm_security_grant, bta_dm_ble_set_bg_conn_type, - bta_dm_ble_set_conn_params, /* BTA_DM_API_BLE_CONN_PARAM_EVT */ - bta_dm_ble_set_conn_scan_params, /* BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT */ - bta_dm_ble_set_scan_params, /* BTA_DM_API_BLE_SCAN_PARAM_EVT */ - bta_dm_ble_set_scan_fil_params, /* BTA_DM_API_BLE_SCAN_FIL_PARAM_EVT */ - bta_dm_ble_observe, /* BTA_DM_API_BLE_OBSERVE_EVT*/ - bta_dm_ble_update_conn_params, /* BTA_DM_API_UPDATE_CONN_PARAM_EVT */ - /*******This handler function added by Yulong at 2016/9/9 to - support the random address setting for the APP******/ - bta_dm_ble_set_rand_address, /*BTA_DM_API_SET_RAND_ADDR_EVT*/ - /*******This handler function added by Yulong at 2016/10/19 to - support stop the ble advertising setting by the APP******/ - bta_dm_ble_stop_advertising, /*BTA_DM_API_BLE_STOP_ADV_EVT*/ + bta_dm_ble_set_conn_params, /* BTA_DM_API_BLE_CONN_PARAM_EVT */ + bta_dm_ble_set_conn_scan_params, /* BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT */ + bta_dm_ble_set_scan_params, /* BTA_DM_API_BLE_SCAN_PARAM_EVT */ + bta_dm_ble_set_scan_fil_params, /* BTA_DM_API_BLE_SCAN_FIL_PARAM_EVT */ + bta_dm_ble_observe, /* BTA_DM_API_BLE_OBSERVE_EVT*/ + bta_dm_ble_update_conn_params, /* BTA_DM_API_UPDATE_CONN_PARAM_EVT */ + /* This handler function added by + Yulong at 2016/9/9 to support the + random address setting for the APP */ + bta_dm_ble_set_rand_address, /* BTA_DM_API_SET_RAND_ADDR_EVT*/ + /* This handler function added by + Yulong at 2016/10/19 to support + stop the ble advertising setting + by the APP */ + bta_dm_ble_stop_advertising, /* BTA_DM_API_BLE_STOP_ADV_EVT*/ #if BLE_PRIVACY_SPT == TRUE - bta_dm_ble_config_local_privacy, /* BTA_DM_API_LOCAL_PRIVACY_EVT */ + bta_dm_ble_config_local_privacy, /* BTA_DM_API_LOCAL_PRIVACY_EVT */ #endif - bta_dm_ble_set_adv_params, /* BTA_DM_API_BLE_ADV_PARAM_EVT */ - bta_dm_ble_set_adv_params_all, /* BTA_DM_API_BLE_ADV_PARAM_All_EVT */ - bta_dm_ble_set_adv_config, /* BTA_DM_API_BLE_SET_ADV_CONFIG_EVT */ - bta_dm_ble_set_scan_rsp, /* BTA_DM_API_BLE_SET_SCAN_RSPT */ - bta_dm_ble_broadcast, /* BTA_DM_API_BLE_BROADCAST_EVT */ - bta_dm_ble_set_data_length, /* BTA_DM_API_SET_DATA_LENGTH_EVT */ + bta_dm_ble_set_adv_params, /* BTA_DM_API_BLE_ADV_PARAM_EVT */ + bta_dm_ble_set_adv_params_all, /* BTA_DM_API_BLE_ADV_PARAM_All_EVT */ + bta_dm_ble_set_adv_config, /* BTA_DM_API_BLE_SET_ADV_CONFIG_EVT */ + /* New function to allow set raw adv + data to HCI */ + bta_dm_ble_set_adv_config_raw, /* BTA_DM_API_BLE_SET_ADV_CONFIG_RAW_EVT */ + bta_dm_ble_set_scan_rsp, /* BTA_DM_API_BLE_SET_SCAN_RSP_EVT */ + /* New function to allow set raw scan + response data to HCI */ + bta_dm_ble_set_scan_rsp_raw, /* BTA_DM_API_BLE_SET_SCAN_RSP_RAW_EVT */ + bta_dm_ble_broadcast, /* BTA_DM_API_BLE_BROADCAST_EVT */ + bta_dm_ble_set_data_length, /* BTA_DM_API_SET_DATA_LENGTH_EVT */ #if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE - bta_dm_cfg_filter_cond, /* BTA_DM_API_CFG_FILTER_COND_EVT */ - bta_dm_scan_filter_param_setup, /* BTA_DM_API_SCAN_FILTER_SETUP_EVT */ - bta_dm_enable_scan_filter, /* BTA_DM_API_SCAN_FILTER_ENABLE_EVT */ + bta_dm_cfg_filter_cond, /* BTA_DM_API_CFG_FILTER_COND_EVT */ + bta_dm_scan_filter_param_setup, /* BTA_DM_API_SCAN_FILTER_SETUP_EVT */ + bta_dm_enable_scan_filter, /* BTA_DM_API_SCAN_FILTER_ENABLE_EVT */ #endif - bta_dm_ble_multi_adv_enb, /* BTA_DM_API_BLE_MULTI_ADV_ENB_EVT*/ - bta_dm_ble_multi_adv_upd_param, /* BTA_DM_API_BLE_MULTI_ADV_PARAM_UPD_EVT */ - bta_dm_ble_multi_adv_data, /* BTA_DM_API_BLE_MULTI_ADV_DATA_EVT */ - btm_dm_ble_multi_adv_disable, /* BTA_DM_API_BLE_MULTI_ADV_DISABLE_EVT */ - bta_dm_ble_setup_storage, /* BTA_DM_API_BLE_SETUP_STORAGE_EVT */ - bta_dm_ble_enable_batch_scan, /* BTA_DM_API_BLE_ENABLE_BATCH_SCAN_EVT */ - bta_dm_ble_disable_batch_scan, /* BTA_DM_API_BLE_DISABLE_BATCH_SCAN_EVT */ - bta_dm_ble_read_scan_reports, /* BTA_DM_API_BLE_READ_SCAN_REPORTS_EVT */ - bta_dm_ble_track_advertiser, /* BTA_DM_API_BLE_TRACK_ADVERTISER_EVT */ - bta_dm_ble_get_energy_info, /* BTA_DM_API_BLE_ENERGY_INFO_EVT */ + bta_dm_ble_multi_adv_enb, /* BTA_DM_API_BLE_MULTI_ADV_ENB_EVT*/ + bta_dm_ble_multi_adv_upd_param, /* BTA_DM_API_BLE_MULTI_ADV_PARAM_UPD_EVT */ + bta_dm_ble_multi_adv_data, /* BTA_DM_API_BLE_MULTI_ADV_DATA_EVT */ + btm_dm_ble_multi_adv_disable, /* BTA_DM_API_BLE_MULTI_ADV_DISABLE_EVT */ + bta_dm_ble_setup_storage, /* BTA_DM_API_BLE_SETUP_STORAGE_EVT */ + bta_dm_ble_enable_batch_scan, /* BTA_DM_API_BLE_ENABLE_BATCH_SCAN_EVT */ + bta_dm_ble_disable_batch_scan, /* BTA_DM_API_BLE_DISABLE_BATCH_SCAN_EVT */ + bta_dm_ble_read_scan_reports, /* BTA_DM_API_BLE_READ_SCAN_REPORTS_EVT */ + bta_dm_ble_track_advertiser, /* BTA_DM_API_BLE_TRACK_ADVERTISER_EVT */ + bta_dm_ble_get_energy_info, /* BTA_DM_API_BLE_ENERGY_INFO_EVT */ #endif - bta_dm_enable_test_mode, /* BTA_DM_API_ENABLE_TEST_MODE_EVT */ - bta_dm_disable_test_mode, /* BTA_DM_API_DISABLE_TEST_MODE_EVT */ - bta_dm_execute_callback, /* BTA_DM_API_EXECUTE_CBACK_EVT */ + bta_dm_enable_test_mode, /* BTA_DM_API_ENABLE_TEST_MODE_EVT */ + bta_dm_disable_test_mode, /* BTA_DM_API_DISABLE_TEST_MODE_EVT */ + bta_dm_execute_callback, /* BTA_DM_API_EXECUTE_CBACK_EVT */ - bta_dm_remove_all_acl, /* BTA_DM_API_REMOVE_ALL_ACL_EVT */ - bta_dm_remove_device, /* BTA_DM_API_REMOVE_DEVICE_EVT */ + bta_dm_remove_all_acl, /* BTA_DM_API_REMOVE_ALL_ACL_EVT */ + bta_dm_remove_device, /* BTA_DM_API_REMOVE_DEVICE_EVT */ }; @@ -161,24 +170,24 @@ enum { /* action function list */ const tBTA_DM_ACTION bta_dm_search_action[] = { - bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */ - bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */ - bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */ - bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */ - bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */ - bta_dm_sdp_result, /* 5 BTA_DM_SDP_RESULT */ - bta_dm_search_cmpl, /* 6 BTA_DM_SEARCH_CMPL */ - bta_dm_free_sdp_db, /* 7 BTA_DM_FREE_SDP_DB */ - bta_dm_disc_result, /* 8 BTA_DM_DISC_RESULT */ - bta_dm_search_result, /* 9 BTA_DM_SEARCH_RESULT */ - bta_dm_queue_search, /* 10 BTA_DM_QUEUE_SEARCH */ - bta_dm_queue_disc, /* 11 BTA_DM_QUEUE_DISC */ - bta_dm_search_clear_queue, /* 12 BTA_DM_SEARCH_CLEAR_QUEUE */ - bta_dm_search_cancel_cmpl, /* 13 BTA_DM_SEARCH_CANCEL_CMPL */ - bta_dm_search_cancel_notify, /* 14 BTA_DM_SEARCH_CANCEL_NOTIFY */ - bta_dm_search_cancel_transac_cmpl, /* 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL */ - bta_dm_disc_rmt_name, /* 16 BTA_DM_DISC_RMT_NAME */ - bta_dm_di_disc /* 17 BTA_DM_API_DI_DISCOVER */ + bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */ + bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */ + bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */ + bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */ + bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */ + bta_dm_sdp_result, /* 5 BTA_DM_SDP_RESULT */ + bta_dm_search_cmpl, /* 6 BTA_DM_SEARCH_CMPL */ + bta_dm_free_sdp_db, /* 7 BTA_DM_FREE_SDP_DB */ + bta_dm_disc_result, /* 8 BTA_DM_DISC_RESULT */ + bta_dm_search_result, /* 9 BTA_DM_SEARCH_RESULT */ + bta_dm_queue_search, /* 10 BTA_DM_QUEUE_SEARCH */ + bta_dm_queue_disc, /* 11 BTA_DM_QUEUE_DISC */ + bta_dm_search_clear_queue, /* 12 BTA_DM_SEARCH_CLEAR_QUEUE */ + bta_dm_search_cancel_cmpl, /* 13 BTA_DM_SEARCH_CANCEL_CMPL */ + bta_dm_search_cancel_notify, /* 14 BTA_DM_SEARCH_CANCEL_NOTIFY */ + bta_dm_search_cancel_transac_cmpl, /* 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL */ + bta_dm_disc_rmt_name, /* 16 BTA_DM_DISC_RMT_NAME */ + bta_dm_di_disc /* 17 BTA_DM_API_DI_DISCOVER */ #if BLE_INCLUDED == TRUE , bta_dm_close_gatt_conn #endif diff --git a/components/bt/bluedroid/bta/include/bta_api.h b/components/bt/bluedroid/bta/include/bta_api.h index 182482ef0f..7385c18674 100644 --- a/components/bt/bluedroid/bta/include/bta_api.h +++ b/components/bt/bluedroid/bta/include/bta_api.h @@ -2050,6 +2050,22 @@ extern void BTA_DmBleSetAdvConfig (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_adv_cfg, tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback); +/******************************************************************************* +** +** Function BTA_DmBleSetAdvConfigRaw +** +** Description This function is called to set raw Advertising data +** +** Parameters p_raw_adv : raw advertising data. +** raw_adv_len : raw advertising data length. +** p_adv_data_cback : set adv data complete callback. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleSetAdvConfigRaw (UINT8 *p_raw_adv, UINT32 raw_adv_len, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback); + /******************************************************************************* ** ** Function BTA_DmBleSetScanRsp @@ -2065,6 +2081,22 @@ extern void BTA_DmBleSetScanRsp (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_adv_cfg, tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback); +/******************************************************************************* +** +** Function BTA_DmBleSetScanRspRaw +** +** Description This function is called to set raw scan response data +** +** Parameters p_raw_scan_rsp : raw scan_rspertising data. +** raw_scan_rsp_len : raw scan_rspertising data length. +** p_scan_rsp_data_cback : set scan_rsp data complete callback. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleSetScanRspRaw (UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_len, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_scan_rsp_data_cback); + /******************************************************************************* ** ** Function BTA_DmBleBroadcast diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c b/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c index 7866ca0f80..bf9ba35a04 100644 --- a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c +++ b/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c @@ -177,6 +177,10 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) blufi_env.prepare_buf = NULL; } + break; + case BTA_GATTS_MTU_EVT: + LOG_DEBUG("MTU size %d\n", p_data->req_data.p_data->mtu); + blufi_env.frag_size = p_data->req_data.p_data->mtu - BLUFI_MTU_RESERVED_SIZE; break; case BTA_GATTS_CONF_EVT: LOG_DEBUG("CONIRM EVT\n"); @@ -198,7 +202,7 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_e2p, (GATT_PERM_READ), - (GATT_PERM_READ | GATT_CHAR_PROP_BIT_NOTIFY), + (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY), NULL, NULL); break; case BLUFI_CHAR_E2P_UUID: /* ESP32 to Phone */ @@ -294,6 +298,7 @@ static tGATT_STATUS btc_blufi_profile_init(void) memset(&blufi_env, 0x0, sizeof(blufi_env)); blufi_env.cbs = store_p; /* if set callback prior, restore the point */ + blufi_env.frag_size = BLUFI_FRAG_DATA_DEFAULT_LEN; /* register the BLUFI profile to the BTA_GATTS module*/ BTA_GATTS_AppRegister(&blufi_app_uuid, blufi_profile_cb); @@ -406,16 +411,16 @@ void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len) int ret; while (remain_len > 0) { - if (remain_len > BLUFI_FRAG_DATA_MAX_LEN) { - hdr = GKI_getbuf(sizeof(struct blufi_hdr) + 2 + BLUFI_FRAG_DATA_MAX_LEN + 2); + if (remain_len > blufi_env.frag_size) { + hdr = GKI_getbuf(sizeof(struct blufi_hdr) + 2 + blufi_env.frag_size + 2); if (hdr == NULL) { LOG_ERROR("%s no mem\n", __func__); return; } hdr->fc = 0x0; - hdr->data_len = BLUFI_FRAG_DATA_MAX_LEN + 2; + hdr->data_len = blufi_env.frag_size + 2; *(uint16_t *)hdr->data = remain_len; - memcpy(hdr->data + 2, &data[total_data_len - remain_len], BLUFI_FRAG_DATA_MAX_LEN); //copy first, easy for check sum + memcpy(hdr->data + 2, &data[total_data_len - remain_len], blufi_env.frag_size); //copy first, easy for check sum hdr->fc |= BLUFI_FC_FRAG; } else { hdr = GKI_getbuf(sizeof(struct blufi_hdr) + remain_len + 2); diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h b/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h index c21b41c4ca..c8b002348d 100644 --- a/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h +++ b/components/bt/bluedroid/btc/profile/esp/blufi/include/blufi_int.h @@ -33,6 +33,7 @@ typedef struct { BD_ADDR remote_bda; UINT32 trans_id; UINT8 congest; + UINT16 frag_size; #define BLUFI_PREPAIR_BUF_MAX_SIZE 1024 uint8_t *prepare_buf; int prepare_len; @@ -160,7 +161,9 @@ typedef struct blufi_frag_hdr blufi_frag_hdr_t; #define BLUFI_FC_IS_REQ_ACK(fc) ((fc) & BLUFI_FC_REQ_ACK_MASK) #define BLUFI_FC_IS_FRAG(fc) ((fc) & BLUFI_FC_FRAG_MASK) -#define BLUFI_FRAG_DATA_MAX_LEN 50 +/* BLUFI HEADER + TOTAL(REMAIN) LENGTH + CRC + L2CAP RESERVED */ +#define BLUFI_MTU_RESERVED_SIZE (sizeof(struct blufi_hdr) + 2 + 2 + 3) +#define BLUFI_FRAG_DATA_DEFAULT_LEN (GATT_DEF_BLE_MTU_SIZE - BLUFI_MTU_RESERVED_SIZE) //function declare void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len); diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 4161567538..339ff68420 100644 --- a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -30,7 +30,7 @@ static inline void btc_gap_ble_cb_to_app(esp_gap_ble_cb_event_t event, esp_ble_g { esp_gap_ble_cb_t btc_gap_ble_cb = (esp_gap_ble_cb_t)btc_profile_cb_get(BTC_PID_GAP_BLE); if (btc_gap_ble_cb) { - btc_gap_ble_cb(event, param); + btc_gap_ble_cb(event, param); } } @@ -303,6 +303,44 @@ static void btc_scan_rsp_data_callback(tBTA_STATUS status) } } +static void btc_adv_data_raw_callback(tBTA_STATUS status) +{ + esp_ble_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT; + param.adv_data_raw_cmpl.status = status; + + ret = btc_transfer_context(&msg, ¶m, + sizeof(esp_ble_gap_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + +static void btc_scan_rsp_data_raw_callback(tBTA_STATUS status) +{ + esp_ble_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT; + param.scan_rsp_data_raw_cmpl.status = status; + + ret = btc_transfer_context(&msg, ¶m, + sizeof(esp_ble_gap_cb_param_t), NULL); + + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + static void btc_ble_set_adv_data(esp_ble_adv_data_t *adv_data, tBTA_SET_ADV_DATA_CMPL_CBACK p_adv_data_cback) { @@ -317,6 +355,18 @@ static void btc_ble_set_adv_data(esp_ble_adv_data_t *adv_data, } } +static void btc_ble_set_adv_data_raw(uint8_t *raw_adv, uint32_t raw_adv_len, + tBTA_SET_ADV_DATA_CMPL_CBACK p_adv_data_cback) +{ + BTA_DmBleSetAdvConfigRaw(raw_adv, raw_adv_len, p_adv_data_cback); +} + +static void btc_ble_set_scan_rsp_data_raw(uint8_t *raw_scan_rsp, uint32_t raw_scan_rsp_len, + tBTA_SET_ADV_DATA_CMPL_CBACK p_scan_rsp_data_cback) +{ + BTA_DmBleSetScanRspRaw(raw_scan_rsp, raw_scan_rsp_len, p_scan_rsp_data_cback); +} + static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params) { tBLE_BD_ADDR peer_addr; @@ -520,6 +570,12 @@ void btc_gap_ble_cb_handler(btc_msg_t *msg) case ESP_GAP_BLE_SCAN_RESULT_EVT: btc_gap_ble_cb_to_app(ESP_GAP_BLE_SCAN_RESULT_EVT, param); break; + case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: + btc_gap_ble_cb_to_app(ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT, param); + break; + case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: + btc_gap_ble_cb_to_app(ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT, param); + break; default: break; @@ -551,6 +607,30 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) } break; } + case BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW: { + btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src; + btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *) p_dest; + + if (src && src->cfg_adv_data_raw.raw_adv && src->cfg_adv_data_raw.raw_adv_len > 0) { + dst->cfg_adv_data_raw.raw_adv = GKI_getbuf(src->cfg_adv_data_raw.raw_adv_len); + if (dst->cfg_adv_data_raw.raw_adv) { + memcpy(dst->cfg_adv_data_raw.raw_adv, src->cfg_adv_data_raw.raw_adv, src->cfg_adv_data_raw.raw_adv_len); + } + } + break; + } + case BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW: { + btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src; + btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *) p_dest; + + if (src && src->cfg_scan_rsp_data_raw.raw_scan_rsp && src->cfg_scan_rsp_data_raw.raw_scan_rsp_len > 0) { + dst->cfg_scan_rsp_data_raw.raw_scan_rsp = GKI_getbuf(src->cfg_scan_rsp_data_raw.raw_scan_rsp_len); + if (dst->cfg_scan_rsp_data_raw.raw_scan_rsp) { + memcpy(dst->cfg_scan_rsp_data_raw.raw_scan_rsp, src->cfg_scan_rsp_data_raw.raw_scan_rsp, src->cfg_scan_rsp_data_raw.raw_scan_rsp_len); + } + } + break; + } default: LOG_ERROR("Unhandled deep copy %d\n", msg->act); break; @@ -576,6 +656,20 @@ static void btc_gap_ble_arg_deep_free(btc_msg_t *msg) } break; } + case BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW: { + uint8_t *raw_adv = ((btc_ble_gap_args_t *)msg->arg)->cfg_adv_data_raw.raw_adv; + if (raw_adv) { + GKI_freebuf(raw_adv); + } + break; + } + case BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW: { + uint8_t *raw_scan_rsp = ((btc_ble_gap_args_t *)msg->arg)->cfg_scan_rsp_data_raw.raw_scan_rsp; + if (raw_scan_rsp) { + GKI_freebuf(raw_scan_rsp); + } + break; + } default: LOG_DEBUG("Unhandled deep free %d\n", msg->act); break; @@ -631,6 +725,16 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) case BTC_GAP_BLE_ACT_SET_DEV_NAME: BTA_DmSetDeviceName(arg->set_dev_name.device_name); break; + case BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW: + btc_ble_set_adv_data_raw(arg->cfg_adv_data_raw.raw_adv, + arg->cfg_adv_data_raw.raw_adv_len, + btc_adv_data_raw_callback); + break; + case BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW: + btc_ble_set_scan_rsp_data_raw(arg->cfg_scan_rsp_data_raw.raw_scan_rsp, + arg->cfg_scan_rsp_data_raw.raw_scan_rsp_len, + btc_scan_rsp_data_raw_callback); + break; default: break; } diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c b/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c index 537be9092c..71e01c76e0 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c +++ b/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c @@ -448,7 +448,7 @@ static void btc_gattc_unreg_for_notify(btc_ble_gattc_args_t *arg) memset(¶m, 0, sizeof(esp_ble_gattc_cb_param_t)); param.unreg_for_notify.status = status; memcpy(¶m.unreg_for_notify.srvc_id, &arg->unreg_for_notify.service_id, sizeof(esp_gatt_srvc_id_t)); - memcpy(¶m.unreg_for_notify.char_id, &arg->unreg_for_notify.service_id, sizeof(esp_gatt_id_t)); + memcpy(¶m.unreg_for_notify.char_id, &arg->unreg_for_notify.char_id, sizeof(esp_gatt_id_t)); btc_gattc_cb_to_app(ESP_GATTC_UNREG_FOR_NOTIFY_EVT, arg->unreg_for_notify.gattc_if, ¶m); } diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h b/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h index 9a35db4083..ea639bcde9 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h @@ -32,6 +32,8 @@ typedef enum { BTC_GAP_BLE_ACT_SET_RAND_ADDRESS, BTC_GAP_BLE_ACT_CONFIG_LOCAL_PRIVACY, BTC_GAP_BLE_ACT_SET_DEV_NAME, + BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW, + BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW, } btc_gap_ble_act_t; /* btc_ble_gap_args_t */ @@ -76,6 +78,16 @@ typedef union { #define ESP_GAP_DEVICE_NAME_MAX (32) char device_name[ESP_GAP_DEVICE_NAME_MAX + 1]; } set_dev_name; + //BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW, + struct config_adv_data_raw_args { + uint8_t *raw_adv; + uint32_t raw_adv_len; + } cfg_adv_data_raw; + //BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW, + struct config_scan_rsp_data_raw_args { + uint8_t *raw_scan_rsp; + uint32_t raw_scan_rsp_len; + } cfg_scan_rsp_data_raw; } btc_ble_gap_args_t; void btc_gap_ble_call_handler(btc_msg_t *msg); diff --git a/components/bt/bluedroid/device/controller.c b/components/bt/bluedroid/device/controller.c index c7fc98d6c8..08564052d8 100644 --- a/components/bt/bluedroid/device/controller.c +++ b/components/bt/bluedroid/device/controller.c @@ -221,6 +221,10 @@ static void start_up(void) } if (HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array)) { + /* set default tx data length to MAX 251 */ + response = AWAIT_COMMAND(packet_factory->make_ble_write_suggested_default_data_length(BTM_BLE_DATA_SIZE_MAX, BTM_BLE_DATA_TX_TIME_MAX)); + packet_parser->parse_generic_command_complete(response); + response = AWAIT_COMMAND(packet_factory->make_ble_read_suggested_default_data_length()); packet_parser->parse_ble_read_suggested_default_data_length_response( response, diff --git a/components/bt/bluedroid/hci/hci_packet_factory.c b/components/bt/bluedroid/hci/hci_packet_factory.c index 6d5592b758..c4bb96b162 100644 --- a/components/bt/bluedroid/hci/hci_packet_factory.c +++ b/components/bt/bluedroid/hci/hci_packet_factory.c @@ -154,6 +154,17 @@ static BT_HDR *make_ble_read_suggested_default_data_length(void) return make_command_no_params(HCI_BLE_READ_DEFAULT_DATA_LENGTH); } +static BT_HDR *make_ble_write_suggested_default_data_length(uint16_t SuggestedMaxTxOctets, uint16_t SuggestedMaxTxTime) +{ + uint8_t *stream; + uint8_t parameter_size = sizeof(uint16_t) + sizeof(uint16_t); + BT_HDR *packet = make_command(HCI_BLE_WRITE_DEFAULT_DATA_LENGTH, parameter_size, &stream); + + UINT16_TO_STREAM(stream, SuggestedMaxTxOctets); + UINT16_TO_STREAM(stream, SuggestedMaxTxTime); + return packet; +} + static BT_HDR *make_ble_set_event_mask(const bt_event_mask_t *event_mask) { uint8_t *stream; @@ -215,6 +226,7 @@ static const hci_packet_factory_t interface = { make_ble_read_local_supported_features, make_ble_read_resolving_list_size, make_ble_read_suggested_default_data_length, + make_ble_write_suggested_default_data_length, make_ble_set_event_mask }; diff --git a/components/bt/bluedroid/hci/include/hci_packet_factory.h b/components/bt/bluedroid/hci/include/hci_packet_factory.h index 879962c2fc..11f0053a58 100644 --- a/components/bt/bluedroid/hci/include/hci_packet_factory.h +++ b/components/bt/bluedroid/hci/include/hci_packet_factory.h @@ -40,6 +40,7 @@ typedef struct { BT_HDR *(*make_ble_read_local_supported_features)(void); BT_HDR *(*make_ble_read_resolving_list_size)(void); BT_HDR *(*make_ble_read_suggested_default_data_length)(void); + BT_HDR *(*make_ble_write_suggested_default_data_length)(uint16_t SuggestedMaxTxOctets, uint16_t SuggestedMaxTxTime); BT_HDR *(*make_ble_set_event_mask)(const bt_event_mask_t *event_mask); } hci_packet_factory_t; diff --git a/components/bt/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/bluedroid/stack/btm/btm_ble_gap.c index 98a8a23689..4cfce3b667 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/bluedroid/stack/btm/btm_ble_gap.c @@ -1298,6 +1298,26 @@ tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p return status; } +/******************************************************************************* +** +** Function BTM_BleWriteScanRspRaw +** +** Description This function is called to write raw scan response data +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleWriteScanRspRaw(UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_len) +{ + if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)raw_scan_rsp_len, p_raw_scan_rsp)) { + return BTM_SUCCESS; + } else { + return BTM_NO_RESOURCES; + } +} + /******************************************************************************* ** ** Function BTM_BleWriteAdvData @@ -1345,6 +1365,27 @@ tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p } +/******************************************************************************* +** +** Function BTM_BleWriteAdvDataRaw +** +** Description This function is called to write raw advertising data. +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleWriteAdvDataRaw(UINT8 *p_raw_adv, UINT32 raw_adv_len) +{ + if (btsnd_hcic_ble_set_adv_data((UINT8)raw_adv_len, p_raw_adv)) { + return BTM_SUCCESS; + } else { + return BTM_NO_RESOURCES; + } +} + + /******************************************************************************* ** ** Function BTM_BleSetRandAddress diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/bluedroid/stack/gatt/gatt_db.c index fd27959d96..03919d483c 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/bluedroid/stack/gatt/gatt_db.c @@ -651,27 +651,28 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, case GATT_UUID_INCLUDE_SERVICE: return GATT_NOT_FOUND; default: - if (p_cur->p_value->attr_val.attr_max_len < length) { + if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len < length) { GATT_TRACE_ERROR("gatts_set_attribute_vaule failt:Invalid value length"); return GATT_INVALID_ATTR_LEN; - } else { + } else if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len > 0) { memcpy(p_cur->p_value->attr_val.attr_val, value, length); p_cur->p_value->attr_val.attr_len = length; + } else { + return GATT_INVALID_ATTR_LEN; } break; } } else { - if (p_cur->p_value->attr_val.attr_max_len < length) { + if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len < length) { GATT_TRACE_ERROR("gatts_set_attribute_vaule failt:Invalid value length"); - } else { + } else if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len > 0) { memcpy(p_cur->p_value->attr_val.attr_val, value, length); p_cur->p_value->attr_val.attr_len = length; + } else { + return GATT_INVALID_ATTR_LEN; } - } - break; - } p_cur = p_cur->p_next; @@ -699,8 +700,9 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, UINT16 *length, UINT8 **value) { tGATT_ATTR16 *p_cur; - GATT_TRACE_DEBUG("***********%s*************\n", __func__); + GATT_TRACE_DEBUG("attr_handle = %x\n", attr_handle); + if (p_db == NULL) { GATT_TRACE_ERROR("gatts_get_attribute_value Fail:p_db is NULL.\n"); return GATT_INVALID_PDU; @@ -713,7 +715,6 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, p_cur = (tGATT_ATTR16 *) p_db->p_attr_list; while (p_cur != NULL) { - LOG_ERROR("p_ur->handle = %x\n", p_cur->handle); if (p_cur->handle == attr_handle) { if (p_cur->uuid_type == GATT_ATTR_UUID_TYPE_16) { @@ -722,7 +723,7 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, case GATT_UUID_INCLUDE_SERVICE: break; default: - if (p_cur->p_value->attr_val.attr_len != 0) { + if (p_cur->p_value && p_cur->p_value->attr_val.attr_len != 0) { *length = p_cur->p_value->attr_val.attr_len; *value = p_cur->p_value->attr_val.attr_val; return GATT_SUCCESS; @@ -748,7 +749,6 @@ tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle, } - p_cur = p_cur->p_next; } @@ -1332,7 +1332,13 @@ static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code, gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_READ, &sr_data); - return (tGATT_STATUS) GATT_PENDING; + + if (need_rsp) { + return (tGATT_STATUS) GATT_PENDING; + } + else{ + return (tGATT_STATUS) GATT_STACK_RSP; + } } else { return (tGATT_STATUS) GATT_BUSY; /* max pending command, application error */ } diff --git a/components/bt/bluedroid/stack/gatt/gatt_sr.c b/components/bt/bluedroid/stack/gatt/gatt_sr.c index a817ad1478..2d34a05045 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/bluedroid/stack/gatt/gatt_sr.c @@ -1073,9 +1073,11 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle, GATTS_REQ_TYPE_WRITE, &sr_data); - if(status == GATT_SUCCESS){ + if (status == GATT_SUCCESS) { attp_send_sr_msg(p_tcb, p_msg); gatt_dequeue_sr_cmd(p_tcb); + } else { + GKI_freebuf(p_msg); } } else { @@ -1159,9 +1161,13 @@ static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, UINT8 gatt_send_error_rsp (p_tcb, reason, op_code, handle, FALSE); gatt_dequeue_sr_cmd(p_tcb); } - } else { + } else if (reason == GATT_SUCCESS || reason == GATT_STACK_RSP) { attp_send_sr_msg(p_tcb, p_msg); gatt_dequeue_sr_cmd(p_tcb); + } else { + if (p_msg) { + GKI_freebuf(p_msg); + } } } diff --git a/components/bt/bluedroid/stack/include/btm_ble_api.h b/components/bt/bluedroid/stack/include/btm_ble_api.h index c6ff180761..6eb078386c 100644 --- a/components/bt/bluedroid/stack/include/btm_ble_api.h +++ b/components/bt/bluedroid/stack/include/btm_ble_api.h @@ -936,6 +936,22 @@ tBTM_STATUS BTM_BleSetAdvParamsStartAdv(UINT16 adv_int_min, UINT16 adv_int_max, tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data); +/******************************************************************************* +** +** Function BTM_BleWriteAdvDataRaw +** +** Description This function is called to write raw advertising data. +** +** Parameters: p_raw_adv : point to raw advertising data +** raw_adv_len : raw advertising data +** +** Returns BTM_SUCCESS means success. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleWriteAdvDataRaw(UINT8 *p_raw_adv, UINT32 raw_adv_len); + + BOOLEAN BTM_BleSetRandAddress(BD_ADDR rand_addr); @@ -1136,6 +1152,20 @@ tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback, tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data); +/******************************************************************************* +** +** Function BTM_BleWriteScanRspRaw +** +** Description This function is called to write raw scan response data +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleWriteScanRspRaw(UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_len); + /******************************************************************************* ** ** Function BTM_BleObserve diff --git a/components/bt/bt.c b/components/bt/bt.c index 5bad45ea2c..6a81d11acc 100644 --- a/components/bt/bt.c +++ b/components/bt/bt.c @@ -27,6 +27,7 @@ #include "esp_task.h" #include "esp_intr.h" #include "esp_attr.h" +#include "esp_phy_init.h" #include "bt.h" #if CONFIG_BT_ENABLED @@ -34,6 +35,11 @@ /* not for user call, so don't put to include file */ extern void btdm_osi_funcs_register(void *osi_funcs); extern void btdm_controller_init(void); +extern void btdm_controller_schedule(void); +extern void btdm_controller_deinit(void); +extern int btdm_controller_enable(esp_bt_mode_t mode); +extern int btdm_controller_disable(esp_bt_mode_t mode); +extern void btdm_rf_bb_init(void); /* VHCI function interface */ typedef struct vhci_host_callback { @@ -70,6 +76,12 @@ struct osi_funcs_t { esp_err_t (* _read_efuse_mac)(uint8_t mac[6]); }; +/* Static variable declare */ +static bool btdm_bb_init_flag = false; +static esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + +static xTaskHandle btControllerTaskHandle; + static portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED; static void IRAM_ATTR interrupt_disable(void) @@ -145,14 +157,87 @@ void esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) static void bt_controller_task(void *pvParam) { btdm_osi_funcs_register(&osi_funcs); + btdm_controller_init(); + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + /* Loop */ + btdm_controller_schedule(); } void esp_bt_controller_init() { + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return; + } + xTaskCreatePinnedToCore(bt_controller_task, "btController", ESP_TASK_BT_CONTROLLER_STACK, NULL, - ESP_TASK_BT_CONTROLLER_PRIO, NULL, 0); + ESP_TASK_BT_CONTROLLER_PRIO, &btControllerTaskHandle, 0); +} + +void esp_bt_controller_deinit(void) +{ + vTaskDelete(btControllerTaskHandle); + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; +} + +esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) +{ + int ret; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + return ESP_ERR_INVALID_STATE; + } + + if (mode != ESP_BT_MODE_BTDM) { + return ESP_ERR_INVALID_ARG; + } + + esp_phy_load_cal_and_init(); + + if (btdm_bb_init_flag == false) { + btdm_bb_init_flag = true; + btdm_rf_bb_init(); /* only initialise once */ + } + + ret = btdm_controller_enable(mode); + if (ret) { + return ESP_ERR_INVALID_STATE; + } + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; + + return ESP_OK; +} + +esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode) +{ + int ret; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (mode != ESP_BT_MODE_BTDM) { + return ESP_ERR_INVALID_ARG; + } + + ret = btdm_controller_disable(mode); + if (ret) { + return ESP_ERR_INVALID_STATE; + } + + esp_phy_rf_deinit(); + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + return ESP_OK; +} + +esp_bt_controller_status_t esp_bt_controller_get_status(void) +{ + return btdm_controller_status; } #endif diff --git a/components/bt/include/bt.h b/components/bt/include/bt.h index 926ecfadcd..2c652466bd 100644 --- a/components/bt/include/bt.h +++ b/components/bt/include/bt.h @@ -23,14 +23,63 @@ extern "C" { #endif +/** + * @brief Bluetooth mode for controller enable/disable + */ +typedef enum { + ESP_BT_MODE_ILDE = 0x00, /*!< Bluetooth is not run */ + ESP_BT_MODE_BLE = 0x01, /*!< Run BLE mode */ + ESP_BT_MODE_CLASSIC_BT = 0x02, /*!< Run Classic BT mode */ + ESP_BT_MODE_BTDM = 0x03, /*!< Run dual mode */ +} esp_bt_mode_t; /** - * @brief Initialize BT controller + * @brief Bluetooth controller enable/disable/initialised/de-initialised status + */ +typedef enum { + ESP_BT_CONTROLLER_STATUS_IDLE = 0, + ESP_BT_CONTROLLER_STATUS_INITED, + ESP_BT_CONTROLLER_STATUS_ENABLED, + ESP_BT_CONTROLLER_STATUS_NUM, +} esp_bt_controller_status_t; + +/** + * @brief Initialize BT controller to allocate task and other resource. * * This function should be called only once, before any other BT functions are called. */ void esp_bt_controller_init(void); +/** + * @brief De-initialize BT controller to free resource and delete task. + * + * This function should be called only once, after any other BT functions are called. + * This function is not whole completed, esp_bt_controller_init cannot called after this function. + */ +void esp_bt_controller_deinit(void); + +/** + * @brief Enable BT controller + * @param mode : the mode(BLE/BT/BTDM) to enable. + * Now only support BTDM. + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode); + +/** + * @brief Disable BT controller + * @param mode : the mode(BLE/BT/BTDM) to disable. + * Now only support BTDM. + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode); + +/** + * @brief Get BT controller is initialised/de-initialised/enabled/disabled + * @return status value + */ +esp_bt_controller_status_t esp_bt_controller_get_status(void); + /** @brief esp_vhci_host_callback * used for vhci call host function to notify what host need to do */ diff --git a/components/bt/lib b/components/bt/lib index 9c1eea6bb0..dbac82b5c2 160000 --- a/components/bt/lib +++ b/components/bt/lib @@ -1 +1 @@ -Subproject commit 9c1eea6bb03adc3b3847fff79c3f017652840a46 +Subproject commit dbac82b5c2694f2639161b0a2b3c0bd8c7d3efc5 diff --git a/components/driver/gpio.c b/components/driver/gpio.c index 4e83705408..f1e724dd57 100644 --- a/components/driver/gpio.c +++ b/components/driver/gpio.c @@ -133,10 +133,10 @@ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type) return ESP_OK; } -esp_err_t gpio_intr_enable(gpio_num_t gpio_num) +static esp_err_t gpio_intr_enable_on_core (gpio_num_t gpio_num, uint32_t core_id) { GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); - if (xPortGetCoreID() == 0) { + if (core_id == 0) { GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr } else { GPIO.pin[gpio_num].int_ena = GPIO_APP_CPU_INTR_ENA; //enable pro cpu intr @@ -144,6 +144,11 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num) return ESP_OK; } +esp_err_t gpio_intr_enable(gpio_num_t gpio_num) +{ + return gpio_intr_enable_on_core (gpio_num, xPortGetCoreID()); +} + esp_err_t gpio_intr_disable(gpio_num_t gpio_num) { GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); @@ -380,7 +385,7 @@ esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void gpio_isr_func[gpio_num].fn = isr_handler; gpio_isr_func[gpio_num].args = args; } - gpio_intr_enable(gpio_num); + gpio_intr_enable_on_core (gpio_num, esp_intr_get_cpu(gpio_isr_handle)); portEXIT_CRITICAL(&gpio_spinlock); return ESP_OK; } diff --git a/components/driver/include/driver/adc.h b/components/driver/include/driver/adc.h index 56bdbc1790..d81be4ff9d 100644 --- a/components/driver/include/driver/adc.h +++ b/components/driver/include/driver/adc.h @@ -49,11 +49,11 @@ typedef enum { } adc1_channel_t; /** - * @brief Configuration ADC1 capture width. + * @brief Configure ADC1 capture width. * - * The configuration is in effect for all channels of ADC1 + * The configuration is for all channels of ADC1 * - * @param width_bit ADC1 + * @param width_bit Bit capture width for ADC1 * * @return * - ESP_OK success @@ -62,10 +62,29 @@ typedef enum { esp_err_t adc1_config_width(adc_bits_width_t width_bit); /** - * @brief Configuration ADC1 capture attenuation of channels. + * @brief Configure the ADC1 channel, including setting attenuation. * - * @param channel the ADC1 channel - * @param atten attenuation + * @note This function also configures the input GPIO pin mux to + * connect it to the ADC1 channel. It must be called before calling + * adc1_get_voltage() for this channel. + * + * The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage, + * usually 3.3V) requires setting >0dB signal attenuation for that ADC channel. + * + * When VDD_A is 3.3V: + * + * - 0dB attenuaton (ADC_ATTEN_0db) gives full-scale voltage 1.1V + * - 2.5dB attenuation (ADC_ATTEN_2_5db) gives full-scale voltage 1.5V + * - 6dB attenuation (ADC_ATTEN_6db) gives full-scale voltage 2.2V + * - 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V (see note below) + * + * @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured + * bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.) + * + * @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage. + * + * @param channel ADC1 channel to configure + * @param atten Attenuation level * * @return * - ESP_OK success @@ -74,46 +93,38 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit); esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten); /** - * @brief ADC1 get the value of the voltage. + * @brief Take an ADC1 reading on a single channel * - * @param channel the ADC1 channel + * @note Call adc1_config_width() before the first time this + * function is called. + * + * @note For a given channel, adc1_config_channel_atten(channel) + * must be called before the first time this function is called. + * + * @param channel ADC1 channel to read * * @return - * - -1 Parameter error - * - Other the value of ADC1 channel + * - -1: Parameter error + * - Other: ADC1 channel reading. */ int adc1_get_voltage(adc1_channel_t channel); /** - * @brief Hall Sensor output value. - * @note - * The Hall Sensor uses Channel_0 and Channel_3 of ADC1. - * So, firstly: please configure ADC1 module by calling adc1_config_width before calling hall_sensor_read. - We recommend that the WIDTH ADC1 be configured as 12Bit, because the values of hall_sensor_read are small and almost the same if WIDTH ADC1 is configured as 9Bit, 10Bit or 11Bit. - * secondly: when you use the hall sensor, please do not use Channel_0 and Channel_3 of ADC1 as - * ADC channels. + * @brief Read Hall Sensor * - * @return the value of hall sensor + * @note The Hall Sensor uses channels 0 and 3 of ADC1. Do not configure + * these channels for use as ADC channels. + * + * @note The ADC1 module must be enabled by calling + * adc1_config_width() before calling hall_sensor_read(). ADC1 + * should be configured for 12 bit readings, as the hall sensor + * readings are low values and do not cover the full range of the + * ADC. + * + * @return The hall sensor reading. */ int hall_sensor_read(); -/** - *----------EXAMPLE TO USE ADC1------------ * - * @code{c} - * adc1_config_width(ADC_WIDTH_12Bit);//config adc1 width - * adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_0db);//config channel0 attenuation - * int val=adc1_get_voltage(ADC1_CHANNEL_0);//get the val of channel0 - * @endcode - **/ - -/** - *----------EXAMPLE TO USE HALL SENSOR------------ * - * @code{c} - * adc1_config_width(ADC_WIDTH_12Bit);//config adc1 width - * int val=hall_sensor_read(); - * @endcode - **/ - #ifdef __cplusplus } #endif diff --git a/components/driver/include/driver/dac.h b/components/driver/include/driver/dac.h index 49758f41b9..ce5a90b3c8 100644 --- a/components/driver/include/driver/dac.h +++ b/components/driver/include/driver/dac.h @@ -29,12 +29,15 @@ typedef enum { } dac_channel_t; /** - * @brief Set Dac output voltage. + * @brief Set DAC output voltage. * - * Dac width is 8bit ,and the voltage max is vdd + * DAC output is 8-bit. Maximum (255) corresponds to VDD. * - * @param channel dac channel - * @param dac_value dac output value + * @note When this function is called, function for the DAC + * channel's GPIO pin is reconfigured for RTC DAC function. + * + * @param channel DAC channel + * @param dac_value DAC output value * * @return * - ESP_OK success @@ -42,13 +45,6 @@ typedef enum { */ esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value); -/** - *----------EXAMPLE TO USE DAC------------ * - * @code{c} - * dac_out_voltage(DAC_CHANNEL_1,200);//the dac out voltage ≈ 200*vdd/255 - * @endcode - **/ - #ifdef __cplusplus } #endif diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index 1472ba8352..485afb696e 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -302,9 +302,9 @@ int gpio_get_level(gpio_num_t gpio_num); esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode); /** - * @brief GPIO set pull + * @brief Configure GPIO pull-up/pull-down resistors * - * User this Function,configure GPIO pull mode,such as pull-up,pull-down + * Only pins that support both input & output have integrated pull-up and pull-down resistors. Input-only GPIOs 34-39 do not. * * @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param pull GPIO pull up/down mode. @@ -317,7 +317,7 @@ esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode); esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); /** - * @brief enable GPIO wake-up function. + * @brief Enable GPIO wake-up function. * * @param gpio_num GPIO number. * @@ -341,15 +341,23 @@ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type); esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num); /** - * @brief register GPIO interrupt handler, the handler is an ISR. + * @brief Register GPIO interrupt handler, the handler is an ISR. * The handler will be attached to the same CPU core that this function is running on. * + * This ISR function is called whenever any GPIO interrupt occurs. See + * the alternative gpio_install_isr_service() and + * gpio_isr_handler_add() API in order to have the driver support + * per-GPIO ISRs. + * * @param fn Interrupt handler function. * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. * @param arg Parameter for handler function - * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will - * be returned here. + * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will be returned here. + * + * \verbatim embed:rst:leading-asterisk + * To disable or remove the ISR, pass the returned handle to the :doc:`interrupt allocation functions `. + * \endverbatim * * @return * - ESP_OK Success ; @@ -402,7 +410,9 @@ esp_err_t gpio_pulldown_en(gpio_num_t gpio_num); esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num); /** - * @brief Install a GPIO ISR service, so we can assign different ISR handler for different pins + * @brief Install the driver's GPIO ISR handler service, which allows per-pin GPIO interrupt handlers. + * + * This function is incompatible with gpio_isr_register() - if that function is used, a single global ISR is registered for all GPIO interrupts. If this function is used, the ISR service provides a global GPIO ISR and individual pin handlers are registered via the gpio_isr_register() function. * * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. @@ -415,17 +425,24 @@ esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num); esp_err_t gpio_install_isr_service(int intr_alloc_flags); /** - * @brief Un-install GPIO ISR service, free the resources. + * @brief Uninstall the driver's GPIO ISR service, freeing related resources. */ void gpio_uninstall_isr_service(); /** - * @brief Add ISR handler for the corresponding GPIO. + * @brief Add ISR handler for the corresponding GPIO pin. * - * Interrupt handlers no longer need to be declared with IRAM_ATTR, unless you pass the ESP_INTR_FLAG_IRAM flag - * when allocating the ISR in gpio_install_isr_service(). - * This ISR handler will be called from an ISR. So there probably is some stack size limit, and this limit - * is smaller compared to a "raw" interrupt handler due to another level of indirection. + * Call this function after using gpio_install_isr_service() to + * install the driver's GPIO ISR handler service. + * + * The pin ISR handlers no longer need to be declared with IRAM_ATTR, + * unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the + * ISR in gpio_install_isr_service(). + * + * This ISR handler will be called from an ISR. So there is a stack + * size limit (configurable as "ISR stack size" in menuconfig). This + * limit is smaller compared to a global GPIO interrupt handler due + * to the additional level of indirection. * * @param gpio_num GPIO number * @param isr_handler ISR handler function for the corresponding GPIO number. @@ -439,7 +456,7 @@ void gpio_uninstall_isr_service(); esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void* args); /** - * @brief Remove ISR handler for the corresponding GPIO. + * @brief Remove ISR handler for the corresponding GPIO pin. * * @param gpio_num GPIO number * diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index d44bb676a3..b904b77140 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -32,9 +32,6 @@ extern "C" { #endif -#define I2S_PIN_NO_CHANGE (-1) - - /** * @brief I2S bit width per sample. * @@ -147,6 +144,8 @@ typedef struct { size_t size; /*!< I2S data size for I2S_DATA event*/ } i2s_event_t; +#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */ + /** * @brief I2S pin number for i2s_set_pin * @@ -160,15 +159,18 @@ typedef struct { typedef intr_handle_t i2s_isr_handle_t; /** - * @brief Set I2S pin number + * @brief Set I2S pin number * - * @note - * Internal signal can be output to multiple GPIO pads - * Only one GPIO pad can connect with input signal + * @note + * The I2S peripheral output signals can be connected to multiple GPIO pads. + * However, the I2S peripheral input signal can only be connected to one GPIO pad. * * @param i2s_num I2S_NUM_0 or I2S_NUM_1 * - * @param pin I2S Pin struct, or NULL for 2-channels, 8-bits DAC pin configuration (GPIO25 & GPIO26) + * @param pin I2S Pin structure, or NULL to set 2-channel 8-bit internal DAC pin configuration (GPIO25 & GPIO26) + * + * Inside the pin configuration structure, set I2S_PIN_NO_CHANGE for any pin where + * the current configuration should not be changed. * * @return * - ESP_OK Success @@ -177,15 +179,17 @@ typedef intr_handle_t i2s_isr_handle_t; esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin); /** - * @brief i2s install and start driver + * @brief Install and start I2S driver. * - * @param i2s_num I2S_NUM_0, I2S_NUM_1 + * @param i2s_num I2S_NUM_0, I2S_NUM_1 * - * @param i2s_config I2S configurations - see i2s_config_t struct + * @param i2s_config I2S configurations - see i2s_config_t struct * - * @param queue_size I2S event queue size/depth. + * @param queue_size I2S event queue size/depth. * - * @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue. + * @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue. + * + * This function must be called before any I2S driver read/write operations. * * @return * - ESP_OK Success @@ -205,68 +209,88 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num); /** - * @brief i2s read data buffer to i2s dma buffer + * @brief Write data to I2S DMA transmit buffer. * * @param i2s_num I2S_NUM_0, I2S_NUM_1 * - * @param src source address to write + * @param src Source address to write from * - * @param size size of data (size in bytes) + * @param size Size of data in bytes * - * @param ticks_to_wait Write timeout + * @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this + * many ticks pass without space becoming available in the DMA + * transmit buffer, then the function will return (note that if the + * data is written to the DMA buffer in pieces, the overall operation + * may still take longer than this timeout.) Pass portMAX_DELAY for no + * timeout. * - * @return number of written bytes + * Format of the data in source buffer is determined by the I2S + * configuration (see i2s_config_t). + * + * @return Number of bytes written, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes written will be less than total size. */ int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait); /** - * @brief i2s write data buffer to i2s dma buffer + * @brief Read data from I2S DMA receive buffer * * @param i2s_num I2S_NUM_0, I2S_NUM_1 * - * @param dest destination address to read + * @param dest Destination address to read into * - * @param size size of data (size in bytes) + * @param size Size of data in bytes * - * @param ticks_to_wait Read timeout + * @param ticks_to_wait RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout. * - * @return number of read bytes + * Format of the data in source buffer is determined by the I2S + * configuration (see i2s_config_t). + * + * @return Number of bytes read, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes read will be less than total size. */ int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait); /** - * @brief i2s push 1 sample to i2s dma buffer, with the size parameter equal to one sample's size in bytes = bits_per_sample/8. + * @brief Push (write) a single sample to the I2S DMA TX buffer. + * + * Size of the sample is determined by the channel_format (mono or stereo)) & bits_per_sample configuration (see i2s_config_t). * * @param i2s_num I2S_NUM_0, I2S_NUM_1 * - * @param sample destination address to write (depend on bits_per_sample, size of sample (in bytes) = 2*bits_per_sample/8) + * @param sample Pointer to buffer containing sample to write. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8. * - * @param ticks_to_wait Push timeout + * @param ticks_to_wait Push timeout in RTOS ticks. If space is not available in the DMA TX buffer within this period, no data is written and function returns 0. * - * @return number of push bytes + * @return Number of bytes successfully pushed to DMA buffer, or ESP_FAIL (-1) for parameter error. Will be either zero or the size of configured sample buffer. */ int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait); /** - * @brief Pop 1 sample to i2s dma buffer, with the size parameter equal to one sample's size in bytes = bits_per_sample/8. + * @brief Pop (read) a single sample from the I2S DMA RX buffer. + * + * Size of the sample is determined by the channel_format (mono or stereo)) & bits_per_sample configuration (see i2s_config_t). * * @param i2s_num I2S_NUM_0, I2S_NUM_1 * - * @param sample destination address to write (depend on bits_per_sample, size of sample (in bytes) = 2*bits_per_sample/8) + * @param sample Buffer sample data will be read into. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8. * - * @param ticks_to_wait Pop timeout + * @param ticks_to_wait Pop timeout in RTOS ticks. If a sample is not available in the DMA buffer within this period, no data is read and function returns zero. * - * @return number of pop bytes + * @return Number of bytes successfully read from DMA buffer, or ESP_FAIL (-1) for parameter error. Byte count will be either zero or the size of the configured sample buffer. + */ int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait); /** - * @brief Set clock rate used for I2S RX and TX + * @brief Set sample rate used for I2S RX and TX. + * + * The bit clock rate is determined by the sample rate and i2s_config_t configuration parameters (number of channels, bits_per_sample). + * + * `bit_clock = rate * (number of channels) * bits_per_sample` * * @param i2s_num I2S_NUM_0, I2S_NUM_1 * - * @param rate I2S clock (ex: 8000, 44100...) + * @param rate I2S sample rate (ex: 8000, 44100...) * * @return * - ESP_OK Success @@ -275,18 +299,9 @@ int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait); esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate); /** - * @brief Start driver + * @brief Stop I2S driver * - * @param i2s_num I2S_NUM_0, I2S_NUM_1 - * -* @return - * - ESP_OK Success - * - ESP_FAIL Parameter error - */ -esp_err_t i2s_start(i2s_port_t i2s_num); - -/** - * @brief Stop driver + * Disables I2S TX/RX, until i2s_start() is called. * * @param i2s_num I2S_NUM_0, I2S_NUM_1 * @@ -297,7 +312,23 @@ esp_err_t i2s_start(i2s_port_t i2s_num); esp_err_t i2s_stop(i2s_port_t i2s_num); /** - * @brief Set the TX DMA buffer contents to all zeroes + * @brief Start I2S driver + * + * It is not necessary to call this function after i2s_driver_install() (it is started automatically), however it is necessary to call it after i2s_stop(). + * + * + * @param i2s_num I2S_NUM_0, I2S_NUM_1 + * +* @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t i2s_start(i2s_port_t i2s_num); + +/** + * @brief Zero the contents of the TX DMA buffer. + * + * Pushes zero-byte samples into the TX DMA buffer, until it is full. * * @param i2s_num I2S_NUM_0, I2S_NUM_1 * @@ -307,72 +338,6 @@ esp_err_t i2s_stop(i2s_port_t i2s_num); */ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); -/***************************EXAMPLE********************************** - * - * - * ----------------EXAMPLE OF I2S SETTING --------------------- - * @code{c} - * - * #include "freertos/queue.h" - * #define I2S_INTR_NUM 17 //choose one interrupt number from soc.h - * int i2s_num = 0; //i2s port number - * i2s_config_t i2s_config = { - * .mode = I2S_MODE_MASTER | I2S_MODE_TX, - * .sample_rate = 44100, - * .bits_per_sample = 16, //16, 32 - * .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //format LEFT_RIGHT - * .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB, - * .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, - * .dma_buf_count = 8, - * .dma_buf_len = 64 - * }; - * - * i2s_pin_config_t pin_config = { - * .bck_io_num = 26, - * .ws_io_num = 25, - * .data_out_num = 22, - * .data_in_num = I2S_PIN_NO_CHANGE - * }; - * - * i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver - * - * i2s_set_pin(i2s_num, &pin_config); - * - * i2s_set_sample_rates(i2s_num, 22050); //set sample rates - * - * - * i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver - *@endcode - * - * ----------------EXAMPLE USING I2S WITH DAC --------------------- - * @code{c} - * - * #include "freertos/queue.h" - * #define I2S_INTR_NUM 17 //choose one interrupt number from soc.h - * int i2s_num = 0; //i2s port number - * i2s_config_t i2s_config = { - * .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, - * .sample_rate = 44100, - * .bits_per_sample = 8, // Only 8-bit DAC support - * .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // - * .communication_format = I2S_COMM_FORMAT_I2S_MSB, - * .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, - * .dma_buf_count = 8, - * .dma_buf_len = 64 - * }; - * - * - * i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver - * - * i2s_set_pin(i2s_num, NULL); //for internal DAC - * - * i2s_set_sample_rates(i2s_num, 22050); //set sample rates - * - * i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver - *@endcode - *-----------------------------------------------------------------------------* - ***************************END OF EXAMPLE**********************************/ - #ifdef __cplusplus } #endif diff --git a/components/driver/include/driver/rtc_io.h b/components/driver/include/driver/rtc_io.h index 3fc3287646..3a27a34765 100644 --- a/components/driver/include/driver/rtc_io.h +++ b/components/driver/include/driver/rtc_io.h @@ -24,7 +24,10 @@ extern "C" { #endif /** - * @brief Pullup/pulldown information for a single GPIO pad + * @brief Pin function information for a single GPIO pad's RTC functions. + * + * This is an internal function of the driver, and is not usually useful + * for external use. */ typedef struct { uint32_t reg; /*!< Register of RTC pad, or 0 if not an RTC GPIO */ @@ -46,10 +49,29 @@ typedef enum { RTC_GPIO_MODE_DISABLED, /*!< Pad (output + input) disable */ } rtc_gpio_mode_t; -#define RTC_GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num < GPIO_PIN_COUNT && rtc_gpio_desc[gpio_num].reg != 0)) //to decide whether it is a valid GPIO number - +/** + * @brief Provides access to a constant table of RTC I/O pin + * function information. + * + * This is an internal function of the driver, and is not usually useful + * for external use. + */ extern const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT]; +/** + * @brief Determine if the specified GPIO is a valid RTC GPIO. + * + * @param gpio_num GPIO number + * @return true if GPIO is valid for RTC GPIO use. talse otherwise. + */ +inline static bool rtc_gpio_is_valid_gpio(gpio_num_t gpio_num) +{ + return gpio_num < GPIO_PIN_COUNT + && rtc_gpio_desc[gpio_num].reg != 0; +} + +#define RTC_GPIO_IS_VALID_GPIO(gpio_num) rtc_gpio_is_valid_gpio(gpio_num) // Deprecated, use rtc_gpio_is_valid_gpio() + /** * @brief Init a GPIO as RTC GPIO * diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 68d02a5e0a..23635df27d 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -469,8 +469,6 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_ * @brief Install UART driver. * * UART ISR handler will be attached to the same CPU core that this function is running on. - * Users should know that which CPU is running and then pick a INUM that is not used by system. - * We can find the information of INUM and interrupt level in soc.h. * * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 * @param rx_buffer_size UART RX ring buffer size, rx_buffer_size should be greater than UART_FIFO_LEN. @@ -644,7 +642,6 @@ esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, u * @code{c} * //1. Setup UART * #include "freertos/queue.h" - * #define UART_INTR_NUM 17 //choose one interrupt number from soc.h * //a. Set UART parameter * int uart_num = 0; //uart port number * uart_config_t uart_config = { diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index 19fd3123a9..3d3cab0682 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -87,7 +87,7 @@ const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = { ---------------------------------------------------------------*/ esp_err_t rtc_gpio_init(gpio_num_t gpio_num) { - RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); // 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module. SET_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, (rtc_gpio_desc[gpio_num].mux)); @@ -100,7 +100,7 @@ esp_err_t rtc_gpio_init(gpio_num_t gpio_num) esp_err_t rtc_gpio_deinit(gpio_num_t gpio_num) { - RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); //Select Gpio as Digital Gpio CLEAR_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, (rtc_gpio_desc[gpio_num].mux)); @@ -131,7 +131,7 @@ static esp_err_t rtc_gpio_output_disable(gpio_num_t gpio_num) static esp_err_t rtc_gpio_input_enable(gpio_num_t gpio_num) { - RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); SET_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, rtc_gpio_desc[gpio_num].ie); portEXIT_CRITICAL(&rtc_spinlock); @@ -141,7 +141,7 @@ static esp_err_t rtc_gpio_input_enable(gpio_num_t gpio_num) static esp_err_t rtc_gpio_input_disable(gpio_num_t gpio_num) { - RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); CLEAR_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, rtc_gpio_desc[gpio_num].ie); portEXIT_CRITICAL(&rtc_spinlock); @@ -152,7 +152,7 @@ static esp_err_t rtc_gpio_input_disable(gpio_num_t gpio_num) esp_err_t rtc_gpio_set_level(gpio_num_t gpio_num, uint32_t level) { int rtc_gpio_num = rtc_gpio_num = rtc_gpio_desc[gpio_num].rtc_num;; - RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); if (level) { WRITE_PERI_REG(RTC_GPIO_OUT_W1TS_REG, (1 << (rtc_gpio_num + RTC_GPIO_OUT_DATA_W1TS_S))); @@ -167,7 +167,7 @@ uint32_t rtc_gpio_get_level(gpio_num_t gpio_num) { uint32_t level = 0; int rtc_gpio_num = rtc_gpio_desc[gpio_num].rtc_num; - RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); level = READ_PERI_REG(RTC_GPIO_IN_REG); @@ -177,7 +177,7 @@ uint32_t rtc_gpio_get_level(gpio_num_t gpio_num) esp_err_t rtc_gpio_set_direction(gpio_num_t gpio_num, rtc_gpio_mode_t mode) { - RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG); switch (mode) { case RTC_GPIO_MODE_INPUT_ONLY: diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 6162edba36..17a68c3235 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -502,6 +502,7 @@ static void IRAM_ATTR spi_intr(void *arg) //We have a transaction. Send it. spi_device_t *dev=host->device[i]; host->cur_trans=trans; + host->cur_cs=i; //We should be done with the transmission. assert(host->hw->cmd.usr == 0); @@ -510,7 +511,7 @@ static void IRAM_ATTR spi_intr(void *arg) trans->rxlength=trans->length; } - //Reconfigure accoding to device settings, but only if we change CSses. + //Reconfigure according to device settings, but only if we change CSses. if (i!=prevCs) { //Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have //clock scaling working. @@ -599,7 +600,7 @@ static void IRAM_ATTR spi_intr(void *arg) } else { data=trans->rx_buffer; } - if (trans->rxlengthrxlength <= THRESH_DMA_TRANS) { //No need for DMA; we'll copy the result out of the work registers directly later. } else { host->hw->user.usr_miso_highpart=0; @@ -624,9 +625,9 @@ static void IRAM_ATTR spi_intr(void *arg) } else { data=(uint32_t *)trans->tx_buffer; } - if (trans->rxlength < 8*32) { + if (trans->length <= THRESH_DMA_TRANS) { //No need for DMA. - for (int x=0; x < trans->rxlength; x+=32) { + for (int x=0; x < trans->length; x+=32) { //Use memcpy to get around alignment issues for txdata uint32_t word; memcpy(&word, &data[x/32], 4); @@ -655,7 +656,7 @@ static void IRAM_ATTR spi_intr(void *arg) host->hw->addr=trans->address & 0xffffffff; } host->hw->user.usr_mosi=(trans->tx_buffer==NULL)?0:1; - host->hw->user.usr_miso=(trans->tx_buffer==NULL)?0:1; + host->hw->user.usr_miso=(trans->rx_buffer==NULL)?0:1; //Call pre-transmission callback, if any if (dev->cfg.pre_cb) dev->cfg.pre_cb(trans); diff --git a/components/driver/test/test_spi_master.c b/components/driver/test/test_spi_master.c index d54cc5a633..cb04af8c97 100644 --- a/components/driver/test/test_spi_master.c +++ b/components/driver/test/test_spi_master.c @@ -80,7 +80,7 @@ TEST_CASE("SPI Master clockdiv calculation routines", "[spi]") } -TEST_CASE("SPI Master test", "[spi]") +TEST_CASE("SPI Master test", "[spi][ignore]") { spi_bus_config_t buscfg={ .mosi_io_num=4, diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 0afe5ba0f8..8aa0ed3b5f 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -1,4 +1,4 @@ -menu "ESP32-specific config" +menu "ESP32-specific" choice ESP32_DEFAULT_CPU_FREQ_MHZ prompt "CPU frequency" @@ -113,7 +113,7 @@ config SYSTEM_EVENT_QUEUE_SIZE config SYSTEM_EVENT_TASK_STACK_SIZE int "Event loop task stack size" - default 2048 + default 4096 help Config system event task stack size in different application. @@ -490,24 +490,38 @@ config SW_COEXIST_ENABLE Recommended for heavy traffic scenarios. Both coexistence configuration options are automatically managed, no user intervention is required. -config ESP32_PHY_AUTO_INIT - bool "Initialize PHY in startup code" + +config ESP32_WIFI_RX_BUFFER_NUM + int "Max number of WiFi RX buffers" depends on WIFI_ENABLED + range 2 25 + default 10 + help + Set the number of WiFi rx buffers. Each buffer takes approximately 1.6KB of RAM. + Larger number for higher throughput but more memory. Smaller number for lower + throughput but less memory. + +config PHY_ENABLED + bool + default y if WIFI_ENABLED || BT_ENABLED + +menu PHY + visible if PHY_ENABLED + +config ESP32_PHY_CALIBRATION_AND_DATA_STORAGE + bool "Do phy calibration and store calibration data in NVS" + depends on PHY_ENABLED default y help - If enabled, PHY will be initialized in startup code, before - app_main function runs. - If this is undesired, disable this option and call esp_phy_init - from the application before enabling WiFi or BT. - - If this option is enabled, startup code will also initialize - NVS prior to initializing PHY. + If this option is enabled, NVS will be initialized and calibration data will be loaded from there. + PHY calibration will be skipped on deep sleep wakeup. If calibration data is not found, full calibration + will be performed and stored in NVS. In all other cases, only partial calibration will be performed. If unsure, choose 'y'. config ESP32_PHY_INIT_DATA_IN_PARTITION bool "Use a partition to store PHY init data" - depends on WIFI_ENABLED + depends on PHY_ENABLED default n help If enabled, PHY init data will be loaded from a partition. @@ -521,22 +535,20 @@ config ESP32_PHY_INIT_DATA_IN_PARTITION into the application binary. If unsure, choose 'n'. - -config ESP32_PHY_MAX_TX_POWER - int "Max TX power (dBm)" + +config ESP32_PHY_MAX_WIFI_TX_POWER + int "Max WiFi TX power (dBm)" range 0 20 default 20 - depends on WIFI_ENABLED + depends on PHY_ENABLED && WIFI_ENABLED help - Set maximum transmit power. Actual transmit power for high + Set maximum transmit power for WiFi radio. Actual transmit power for high data rates may be lower than this setting. -config ESP32_WIFI_RX_BUFFER_NUM - int "Max number of WiFi RX buffers" - depends on WIFI_ENABLED - range 2 25 - default 25 - help - Set the number of WiFi rx buffers. Each buffer takes approximately 1.6KB of RAM. - Larger number for higher throughput but more memory. Smaller number for lower - throughput but less memory. +config ESP32_PHY_MAX_TX_POWER + int + depends on PHY_ENABLED + default 20 if !WIFI_ENABLED + default ESP32_PHY_MAX_WIFI_TX_POWER if WIFI_ENABLED + +endmenu diff --git a/components/esp32/component.mk b/components/esp32/component.mk index e1cd2c6524..e7a88571ff 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -3,16 +3,14 @@ # COMPONENT_SRCDIRS := . hwcrypto -LIBS := core rtc phy -ifdef CONFIG_BT_ENABLED -LIBS += coexist +LIBS := core rtc rtc_clk +ifdef CONFIG_PHY_ENABLED # BT || WIFI +LIBS += phy coexist endif ifdef CONFIG_WIFI_ENABLED LIBS += net80211 pp wpa smartconfig coexist wps wpa2 endif -LIBS := $(sort $(LIBS)) # de-duplicate, we can handle different orders here - LINKER_SCRIPTS += esp32.common.ld esp32.rom.ld esp32.peripherals.ld ifeq ("$(CONFIG_NEWLIB_NANO_FORMAT)","y") diff --git a/components/esp32/core_dump.c b/components/esp32/core_dump.c index 85301f4dd6..ecc658ebdc 100644 --- a/components/esp32/core_dump.c +++ b/components/esp32/core_dump.c @@ -26,16 +26,17 @@ #if CONFIG_ESP32_ENABLE_COREDUMP #define LOG_LOCAL_LEVEL CONFIG_ESP32_CORE_DUMP_LOG_LEVEL #include "esp_log.h" -const static char *TAG = "esp_core_dump"; +const static DRAM_ATTR char TAG[] = "esp_core_dump"; -#define ESP_COREDUMP_LOGE( format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { ets_printf(LOG_FORMAT(E, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); } -#define ESP_COREDUMP_LOGW( format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { ets_printf(LOG_FORMAT(W, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); } -#define ESP_COREDUMP_LOGI( format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { ets_printf(LOG_FORMAT(I, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); } -#define ESP_COREDUMP_LOGD( format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { ets_printf(LOG_FORMAT(D, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); } -#define ESP_COREDUMP_LOGV( format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { ets_printf(LOG_FORMAT(V, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); } +#define ESP_COREDUMP_LOG( level, format, ... ) if (LOG_LOCAL_LEVEL >= level) { ets_printf(DRAM_STR(format), esp_log_early_timestamp(), (const char *)TAG, ##__VA_ARGS__); } +#define ESP_COREDUMP_LOGE( format, ... ) ESP_COREDUMP_LOG(ESP_LOG_ERROR, LOG_FORMAT(E, format), ##__VA_ARGS__) +#define ESP_COREDUMP_LOGW( format, ... ) ESP_COREDUMP_LOG(ESP_LOG_WARN, LOG_FORMAT(W, format), ##__VA_ARGS__) +#define ESP_COREDUMP_LOGI( format, ... ) ESP_COREDUMP_LOG(ESP_LOG_INFO, LOG_FORMAT(I, format), ##__VA_ARGS__) +#define ESP_COREDUMP_LOGD( format, ... ) ESP_COREDUMP_LOG(ESP_LOG_DEBUG, LOG_FORMAT(D, format), ##__VA_ARGS__) +#define ESP_COREDUMP_LOGV( format, ... ) ESP_COREDUMP_LOG(ESP_LOG_VERBOSE, LOG_FORMAT(V, format), ##__VA_ARGS__) #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH -#define ESP_COREDUMP_LOG_PROCESS( format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { ets_printf(LOG_FORMAT(D, format), esp_log_early_timestamp(), TAG, ##__VA_ARGS__); } +#define ESP_COREDUMP_LOG_PROCESS( format, ... ) ESP_COREDUMP_LOGD(format, ##__VA_ARGS__) #else #define ESP_COREDUMP_LOG_PROCESS( format, ... ) do{/*(__VA_ARGS__);*/}while(0) #endif @@ -345,8 +346,9 @@ void esp_core_dump_to_flash(XtExcFrame *frame) #endif #if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART + static void esp_core_dump_b64_encode(const uint8_t *src, uint32_t src_len, uint8_t *dst) { - static const char *b64 = + const static DRAM_ATTR char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int i, j, a, b, c; @@ -373,14 +375,14 @@ static void esp_core_dump_b64_encode(const uint8_t *src, uint32_t src_len, uint8 static esp_err_t esp_core_dump_uart_write_start(void *priv) { esp_err_t err = ESP_OK; - ets_printf("================= CORE DUMP START =================\r\n"); + ets_printf(DRAM_STR("================= CORE DUMP START =================\r\n")); return err; } static esp_err_t esp_core_dump_uart_write_end(void *priv) { esp_err_t err = ESP_OK; - ets_printf("================= CORE DUMP END =================\r\n"); + ets_printf(DRAM_STR("================= CORE DUMP END =================\r\n")); return err; } @@ -398,7 +400,7 @@ static esp_err_t esp_core_dump_uart_write_data(void *priv, void * data, uint32_t memcpy(tmp, addr, len); esp_core_dump_b64_encode((const uint8_t *)tmp, len, (uint8_t *)buf); addr += len; - ets_printf("%s\r\n", buf); + ets_printf(DRAM_STR("%s\r\n"), buf); } return err; @@ -427,7 +429,8 @@ void esp_core_dump_to_uart(XtExcFrame *frame) wr_cfg.priv = NULL; //Make sure txd/rxd are enabled - gpio_pullup_dis(1); + // use direct reg access instead of gpio_pullup_dis which can cause exception when flash cache is disabled + REG_CLR_BIT(GPIO_PIN_REG_1, FUN_PU); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD); @@ -438,10 +441,6 @@ void esp_core_dump_to_uart(XtExcFrame *frame) tm_cur = xthal_get_ccount() / (XT_CLOCK_FREQ / 1000); if (tm_cur >= tm_end) break; - /* Feed the Cerberus. */ - TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed = 1; - TIMERG0.wdt_wprotect = 0; ch = esp_core_dump_uart_get_char(); } ESP_COREDUMP_LOGI("Print core dump to uart..."); @@ -455,18 +454,18 @@ void esp_core_dump_init() #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH const esp_partition_t *core_part; - ESP_LOGI(TAG, "Init core dump to flash"); + ESP_COREDUMP_LOGI("Init core dump to flash"); core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, NULL); if (!core_part) { - ESP_LOGE(TAG, "No core dump partition found!"); + ESP_COREDUMP_LOGE("No core dump partition found!"); return; } - ESP_LOGI(TAG, "Found partition '%s' @ %x %d bytes", core_part->label, core_part->address, core_part->size); + ESP_COREDUMP_LOGI("Found partition '%s' @ %x %d bytes", core_part->label, core_part->address, core_part->size); s_core_part_start = core_part->address; s_core_part_size = core_part->size; #endif #if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART - ESP_LOGI(TAG, "Init core dump to UART"); + ESP_COREDUMP_LOGI("Init core dump to UART"); #endif } diff --git a/components/esp32/cpu_freq.c b/components/esp32/cpu_freq.c index 7618f147af..f5ccd13df7 100644 --- a/components/esp32/cpu_freq.c +++ b/components/esp32/cpu_freq.c @@ -17,7 +17,6 @@ #include "rom/ets_sys.h" #include "rom/uart.h" #include "sdkconfig.h" -#include "phy.h" #include "rtc.h" #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" @@ -32,7 +31,6 @@ void esp_set_cpu_freq(void) { uint32_t freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; - phy_get_romfunc_addr(); // freq will be changed to 40MHz in rtc_init_lite, // wait uart tx finish, otherwise some uart output will be lost diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index b5e896e573..cf20083508 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -73,9 +73,6 @@ static bool app_cpu_started = false; static void do_global_ctors(void); static void main_task(void* args); extern void app_main(void); -#if CONFIG_ESP32_PHY_AUTO_INIT -static void do_phy_init(); -#endif extern int _bss_start; extern int _bss_end; @@ -175,7 +172,9 @@ void start_cpu0_default(void) trax_start_trace(TRAX_DOWNCOUNT_WORDS); #endif esp_set_cpu_freq(); // set CPU frequency configured in menuconfig +#ifndef CONFIG_CONSOLE_UART_NONE uart_div_modify(CONFIG_CONSOLE_UART_NUM, (APB_CLK_FREQ << 4) / CONFIG_CONSOLE_UART_BAUDRATE); +#endif #if CONFIG_BROWNOUT_DET esp_brownout_init(); #endif @@ -208,17 +207,6 @@ void start_cpu0_default(void) /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); -#if CONFIG_ESP32_PHY_AUTO_INIT - nvs_flash_init(); - do_phy_init(); -#endif - -#if CONFIG_SW_COEXIST_ENABLE - if (coex_init() == ESP_OK) { - coexist_set_enable(true); - } -#endif - #if CONFIG_ESP32_ENABLE_COREDUMP esp_core_dump_init(); #endif @@ -266,39 +254,3 @@ static void main_task(void* args) vTaskDelete(NULL); } -#if CONFIG_ESP32_PHY_AUTO_INIT -static void do_phy_init() -{ - esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; - if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { - calibration_mode = PHY_RF_CAL_NONE; - } - const esp_phy_init_data_t* init_data = esp_phy_get_init_data(); - if (init_data == NULL) { - ESP_LOGE(TAG, "failed to obtain PHY init data"); - abort(); - } - esp_phy_calibration_data_t* cal_data = - (esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1); - if (cal_data == NULL) { - ESP_LOGE(TAG, "failed to allocate memory for RF calibration data"); - abort(); - } - esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); - if (err != ESP_OK) { - ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); - calibration_mode = PHY_RF_CAL_FULL; - } - - esp_phy_init(init_data, calibration_mode, cal_data); - - if (calibration_mode != PHY_RF_CAL_NONE) { - err = esp_phy_store_cal_data_to_nvs(cal_data); - } else { - err = ESP_OK; - } - esp_phy_release_init_data(init_data); - free(cal_data); // PHY maintains a copy of calibration data, so we can free this -} -#endif //CONFIG_ESP32_PHY_AUTO_INIT - diff --git a/components/esp32/crosscore_int.c b/components/esp32/crosscore_int.c index 1e131eeef7..f75f0eba7d 100644 --- a/components/esp32/crosscore_int.c +++ b/components/esp32/crosscore_int.c @@ -82,7 +82,7 @@ void esp_crosscore_int_init() { assert(err == ESP_OK); } -void esp_crosscore_int_send_yield(int coreId) { +void IRAM_ATTR esp_crosscore_int_send_yield(int coreId) { assert(coreId +#include #include "esp_err.h" #ifdef __cplusplus @@ -192,7 +193,7 @@ void esp_phy_release_init_data(const esp_phy_init_data_t* data); * mechanism for loading calibration data, disable * "Initialize PHY in startup code" option in menuconfig and call esp_phy_init * function from the application. For an example usage of esp_phy_init and - * this function, see do_phy_init function in cpu_start.c + * this function, see esp_phy_store_cal_data_to_nvs function in cpu_start.c * * @param out_cal_data pointer to calibration data structure to be filled with * loaded data. @@ -220,28 +221,39 @@ esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_dat esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data); /** - * @brief Initialize PHY module + * @brief Initialize PHY and RF module * - * PHY module should be initialized in order to use WiFi or BT. - * If "Initialize PHY in startup code" option is set in menuconfig, - * this function will be called automatically before app_main is called, - * using parameters obtained from esp_phy_get_init_data. - * - * Applications which don't need to enable PHY on every start up should - * disable this menuconfig option and call esp_phy_init before calling - * esp_wifi_init or esp_bt_controller_init. See do_phy_init function in - * cpu_start.c for an example of using this function. + * PHY and RF module should be initialized in order to use WiFi or BT. + * Now PHY and RF initializing job is done automatically when start WiFi or BT. Users should not + * call this API in their application. * * @param init_data PHY parameters. Default set of parameters can * be obtained by calling esp_phy_get_default_init_data * function. * @param mode Calibration mode (Full, partial, or no calibration) * @param[inout] calibration_data + * @param is_sleep WiFi wakes up from sleep or not + * @return ESP_OK on success. + * @return ESP_FAIL on fail. + */ +esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, + esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data, bool is_sleep); + +/** + * @brief De-initialize PHY and RF module + * + * PHY module should be de-initialized in order to shutdown WiFi or BT. + * Now PHY and RF de-initializing job is done automatically when stop WiFi or BT. Users should not + * call this API in their application. + * * @return ESP_OK on success. */ -esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, - esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data); +esp_err_t esp_phy_rf_deinit(void); +/** + * @brief Load calibration data from NVS and initialize PHY and RF module + */ +void esp_phy_load_cal_and_init(void); #ifdef __cplusplus } diff --git a/components/esp32/include/esp_system.h b/components/esp32/include/esp_system.h index e1f46de803..30701761ad 100644 --- a/components/esp32/include/esp_system.h +++ b/components/esp32/include/esp_system.h @@ -124,7 +124,12 @@ esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__ ((deprecated)); */ const char* system_get_sdk_version(void) __attribute__ ((deprecated)); - +/** + * Get IDF version + * + * @return constant string from IDF_VER + */ +const char* esp_get_idf_version(void); #ifdef __cplusplus } diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index 8d4fa17bb7..0f7e2996e8 100755 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -130,6 +130,7 @@ esp_err_t esp_wifi_init(wifi_init_config_t *config); * Free all resource allocated in esp_wifi_init and stop WiFi task * * @attention 1. This API should be called if you want to remove WiFi driver from the system + * @attention 2. This API can not be called yet and will be done in the future. * * @return ESP_OK: succeed */ diff --git a/components/esp32/include/soc/ledc_struct.h b/components/esp32/include/soc/ledc_struct.h index d119289acd..c52f670770 100644 --- a/components/esp32/include/soc/ledc_struct.h +++ b/components/esp32/include/soc/ledc_struct.h @@ -122,6 +122,7 @@ typedef volatile struct { uint32_t lstimer1_ovf: 1; /*The interrupt status bit for low speed channel1 counter overflow event.*/ uint32_t lstimer2_ovf: 1; /*The interrupt status bit for low speed channel2 counter overflow event.*/ uint32_t lstimer3_ovf: 1; /*The interrupt status bit for low speed channel3 counter overflow event.*/ + uint32_t duty_chng_end_hsch0: 1; /*The interrupt enable bit for high speed channel 0 duty change done event.*/ uint32_t duty_chng_end_hsch1: 1; /*The interrupt status bit for high speed channel 1 duty change done event.*/ uint32_t duty_chng_end_hsch2: 1; /*The interrupt status bit for high speed channel 2 duty change done event.*/ uint32_t duty_chng_end_hsch3: 1; /*The interrupt status bit for high speed channel 3 duty change done event.*/ diff --git a/components/esp32/include/soc/soc.h b/components/esp32/include/soc/soc.h index 3e0360e249..1b3e35dd47 100755 --- a/components/esp32/include/soc/soc.h +++ b/components/esp32/include/soc/soc.h @@ -268,10 +268,10 @@ * 2 1 extern level * 3 1 extern level * 4 1 extern level WBB - * 5 1 extern level BT Controller + * 5 1 extern level BT/BLE Controller * 6 1 timer FreeRTOS Tick(L1) FreeRTOS Tick(L1) * 7 1 software Reserved Reserved - * 8 1 extern level BLE Controller + * 8 1 extern level BT/BLE BB(RX/TX) * 9 1 extern level * 10 1 extern edge Internal Timer * 11 3 profiling diff --git a/components/esp32/intr_alloc.c b/components/esp32/intr_alloc.c index 1cb2fba5d9..b35973144c 100644 --- a/components/esp32/intr_alloc.c +++ b/components/esp32/intr_alloc.c @@ -89,12 +89,6 @@ typedef struct { #define INT15RES INTDESC_SPECIAL #endif -#if CONFIG_FREERTOS_CORETIMER_2 -#define INT16RES INTDESC_RESVD -#else -#define INT16RES INTDESC_SPECIAL -#endif - //This is basically a software-readable version of the interrupt usage table in include/soc/soc.h const static int_desc_t int_desc[32]={ { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //0 @@ -113,7 +107,7 @@ const static int_desc_t int_desc[32]={ { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //13 { 7, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //14, NMI { 3, INTTP_NA, {INT15RES, INT15RES } }, //15 - { 5, INTTP_NA, {INT16RES, INT16RES } }, //16 + { 5, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL} }, //16 { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //17 { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //18 { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //19 @@ -692,7 +686,7 @@ esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle) } -void esp_intr_noniram_disable() +void IRAM_ATTR esp_intr_noniram_disable() { int oldint; int cpu=xPortGetCoreID(); @@ -706,12 +700,12 @@ void esp_intr_noniram_disable() "and a3,%0,%1\n" //mask ints that need disabling "wsr a3,INTENABLE\n" //write back "rsync\n" - :"=r"(oldint):"r"(intmask):"a3"); + :"=&r"(oldint):"r"(intmask):"a3"); //Save which ints we did disable non_iram_int_disabled[cpu]=oldint&non_iram_int_mask[cpu]; } -void esp_intr_noniram_enable() +void IRAM_ATTR esp_intr_noniram_enable() { int cpu=xPortGetCoreID(); int intmask=non_iram_int_disabled[cpu]; diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index 8cc3b5b22e..bc28e5ca99 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -80,10 +80,17 @@ SECTIONS *(.iram1 .iram1.*) *libfreertos.a:(.literal .text .literal.* .text.*) *libesp32.a:panic.o(.literal .text .literal.* .text.*) + *libesp32.a:core_dump.o(.literal .text .literal.* .text.*) *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) - *libpp.a:(.literal .text .literal.* .text.*) + *librtc_clk.a:(.literal .text .literal.* .text.*) + *libpp.a:pp.o(.literal .text .literal.* .text.*) + *libpp.a:lmac.o(.literal .text .literal.* .text.*) + *libpp.a:wdev.o(.literal .text .literal.* .text.*) + *libcore.a:ets_timer.o(.literal .text .literal.* .text.*) + *libnet80211.a:ieee80211_misc.o(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) + *libcoexist.a:(.literal .text .literal.* .text.*) _iram_text_end = ABSOLUTE(.); } > iram0_0_seg diff --git a/components/esp32/lib b/components/esp32/lib index b26cd21764..ed85cf9156 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit b26cd217641acf08da932f4de8e858083ea83113 +Subproject commit ed85cf9156f2ef358c29d07fb849a73c5758eecb diff --git a/components/esp32/panic.c b/components/esp32/panic.c index 6180770bd6..4f0497d6ea 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -267,7 +267,7 @@ static void reconfigureAllWdts() TIMERG1.wdt_wprotect = 0; } -#if CONFIG_ESP32_PANIC_GDBSTUB || CONFIG_ESP32_PANIC_PRINT_HALT +#if CONFIG_ESP32_PANIC_GDBSTUB || CONFIG_ESP32_PANIC_PRINT_HALT || CONFIG_ESP32_ENABLE_COREDUMP /* This disables all the watchdogs for when we call the gdbstub. */ @@ -367,11 +367,15 @@ static void commonErrorHandler(XtExcFrame *frame) panicPutStr("Entering gdb stub now.\r\n"); esp_gdbstub_panic_handler(frame); #else +#if CONFIG_ESP32_ENABLE_COREDUMP + disableAllWdts(); #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH esp_core_dump_to_flash(frame); #endif #if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART && !CONFIG_ESP32_PANIC_SILENT_REBOOT esp_core_dump_to_uart(frame); +#endif + reconfigureAllWdts(); #endif #if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT panicPutStr("Rebooting...\r\n"); diff --git a/components/esp32/phy.h b/components/esp32/phy.h index 81990f2e36..c0affb36ef 100644 --- a/components/esp32/phy.h +++ b/components/esp32/phy.h @@ -25,8 +25,7 @@ extern "C" { */ /** - * @brief Initialize function pointer table in PHY library. - * @note This function should be called before register_chipv7_phy. + * @brief Return ROM function pointer table from PHY library. */ void phy_get_romfunc_addr(void); diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index 07a455d501..34e1a9f00e 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -17,7 +17,10 @@ #include #include +#include + #include "rom/ets_sys.h" +#include "rom/rtc.h" #include "soc/dport_reg.h" #include "esp_err.h" @@ -25,31 +28,71 @@ #include "esp_system.h" #include "esp_log.h" #include "nvs.h" +#include "nvs_flash.h" #include "sdkconfig.h" -#ifdef CONFIG_WIFI_ENABLED +#ifdef CONFIG_PHY_ENABLED #include "phy.h" #include "phy_init_data.h" +#include "rtc.h" +#include "esp_coexist.h" static const char* TAG = "phy_init"; +/* Count value to indicate if there is peripheral that has initialized PHY and RF */ +static int s_phy_rf_init_count = 0; +static bool s_mac_rst_flag = false; -esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, - esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data) +static _lock_t s_phy_rf_init_lock; + +esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, + esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data, bool is_sleep) { - assert(init_data); - assert(calibration_data); - // Initialize PHY pointer table - phy_get_romfunc_addr(); - REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); - REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); - // Enable WiFi peripheral clock - SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); - ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", - init_data, calibration_data, mode); - phy_set_wifi_mode_only(0); - register_chipv7_phy(init_data, calibration_data, mode); - coex_bt_high_prio(); + assert((s_phy_rf_init_count <= 1) && (s_phy_rf_init_count >= 0)); + + _lock_acquire(&s_phy_rf_init_lock); + if (s_phy_rf_init_count == 0) { + if (is_sleep == false) { + if (s_mac_rst_flag == false) { + s_mac_rst_flag = true; + REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); + REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); + } + } + // Enable WiFi peripheral clock + SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); + ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", + init_data, calibration_data, mode); + phy_set_wifi_mode_only(0); + register_chipv7_phy(init_data, calibration_data, mode); + coex_bt_high_prio(); + } else { +#if CONFIG_SW_COEXIST_ENABLE + coex_init(); +#endif + } + s_phy_rf_init_count++; + _lock_release(&s_phy_rf_init_lock); + return ESP_OK; +} + +esp_err_t esp_phy_rf_deinit(void) +{ + assert((s_phy_rf_init_count <= 2) && (s_phy_rf_init_count >= 1)); + + _lock_acquire(&s_phy_rf_init_lock); + if (s_phy_rf_init_count == 1) { + // Disable PHY and RF. TODO: convert this function to another one. + pm_close_rf(); + // Disable WiFi peripheral clock + CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); + } else { +#if CONFIG_SW_COEXIST_ENABLE + coex_deinit(); +#endif + } + s_phy_rf_init_count--; + _lock_release(&s_phy_rf_init_lock); return ESP_OK; } @@ -221,4 +264,43 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, return err; } -#endif // CONFIG_WIFI_ENABLED +void esp_phy_load_cal_and_init(void) +{ +#ifdef CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE + nvs_flash_init(); + esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; + if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { + calibration_mode = PHY_RF_CAL_NONE; + } + const esp_phy_init_data_t* init_data = esp_phy_get_init_data(); + if (init_data == NULL) { + ESP_LOGE(TAG, "failed to obtain PHY init data"); + abort(); + } + esp_phy_calibration_data_t* cal_data = + (esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1); + if (cal_data == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for RF calibration data"); + abort(); + } + esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); + if (err != ESP_OK) { + ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); + calibration_mode = PHY_RF_CAL_FULL; + } + + esp_phy_rf_init(init_data, calibration_mode, cal_data, false); + + if (calibration_mode != PHY_RF_CAL_NONE && err != ESP_OK) { + err = esp_phy_store_cal_data_to_nvs(cal_data); + } else { + err = ESP_OK; + } + esp_phy_release_init_data(init_data); + free(cal_data); // PHY maintains a copy of calibration data, so we can free this +#else + esp_phy_rf_init(NULL, PHY_RF_CAL_NONE, NULL, false); +#endif +} + +#endif // CONFIG_PHY_ENABLED diff --git a/components/esp32/rtc.h b/components/esp32/rtc.h index e1cf33522d..f21d0da83e 100644 --- a/components/esp32/rtc.h +++ b/components/esp32/rtc.h @@ -135,6 +135,10 @@ void rtc_slp_prep_lite(uint32_t deep_slp, uint32_t cpu_lp_mode); */ uint32_t rtc_sleep(uint32_t cycles_h, uint32_t cycles_l, uint32_t wakeup_opt, uint32_t reject_opt); +/** + * @brief Shutdown PHY and RF. TODO: convert this function to another one. + */ +void pm_close_rf(void); #ifdef __cplusplus } diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index 2f834a9eac..d984af78a7 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -179,4 +179,8 @@ const char* system_get_sdk_version(void) return "master"; } +const char* esp_get_idf_version(void) +{ + return IDF_VER; +} diff --git a/components/esp32/test/test_ahb_arb.c b/components/esp32/test/test_ahb_arb.c index 65f4906fd5..21cf6d7781 100644 --- a/components/esp32/test/test_ahb_arb.c +++ b/components/esp32/test/test_ahb_arb.c @@ -269,7 +269,7 @@ static void tskTwo(void *pvParameters) } -TEST_CASE("S32C1I vs AHB test (needs I2S)", "[hw]") +TEST_CASE("S32C1I vs AHB test (needs I2S)", "[hw][ignore]") { int i; TaskHandle_t th[3]; diff --git a/components/esp32/test/test_deep_sleep.c b/components/esp32/test/test_deep_sleep.c index a47b6daf3f..d892177dc4 100644 --- a/components/esp32/test/test_deep_sleep.c +++ b/components/esp32/test/test_deep_sleep.c @@ -4,7 +4,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -TEST_CASE("esp_deepsleep works", "[deepsleep]") +TEST_CASE("esp_deepsleep works", "[deepsleep][ignore]") { esp_deep_sleep(2000000); } @@ -25,20 +25,20 @@ static void do_deep_sleep_from_app_cpu() } } -TEST_CASE("wake up using timer", "[deepsleep]") +TEST_CASE("wake up using timer", "[deepsleep][ignore]") { esp_deep_sleep_enable_timer_wakeup(2000000); esp_deep_sleep_start(); } -TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep]") +TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][ignore]") { esp_deep_sleep_enable_timer_wakeup(2000000); do_deep_sleep_from_app_cpu(); } -TEST_CASE("wake up using ext0 (13 high)", "[deepsleep]") +TEST_CASE("wake up using ext0 (13 high)", "[deepsleep][ignore]") { ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); ESP_ERROR_CHECK(gpio_pullup_dis(GPIO_NUM_13)); @@ -47,7 +47,7 @@ TEST_CASE("wake up using ext0 (13 high)", "[deepsleep]") esp_deep_sleep_start(); } -TEST_CASE("wake up using ext0 (13 low)", "[deepsleep]") +TEST_CASE("wake up using ext0 (13 low)", "[deepsleep][ignore]") { ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); ESP_ERROR_CHECK(gpio_pullup_en(GPIO_NUM_13)); @@ -56,7 +56,7 @@ TEST_CASE("wake up using ext0 (13 low)", "[deepsleep]") esp_deep_sleep_start(); } -TEST_CASE("wake up using ext1 when RTC_PERIPH is off (13 high)", "[deepsleep]") +TEST_CASE("wake up using ext1 when RTC_PERIPH is off (13 high)", "[deepsleep][ignore]") { // This test needs external pulldown ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); @@ -64,7 +64,7 @@ TEST_CASE("wake up using ext1 when RTC_PERIPH is off (13 high)", "[deepsleep]") esp_deep_sleep_start(); } -TEST_CASE("wake up using ext1 when RTC_PERIPH is off (13 low)", "[deepsleep]") +TEST_CASE("wake up using ext1 when RTC_PERIPH is off (13 low)", "[deepsleep][ignore]") { // This test needs external pullup ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); @@ -72,7 +72,7 @@ TEST_CASE("wake up using ext1 when RTC_PERIPH is off (13 low)", "[deepsleep]") esp_deep_sleep_start(); } -TEST_CASE("wake up using ext1 when RTC_PERIPH is on (13 high)", "[deepsleep]") +TEST_CASE("wake up using ext1 when RTC_PERIPH is on (13 high)", "[deepsleep][ignore]") { ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); ESP_ERROR_CHECK(gpio_pullup_dis(GPIO_NUM_13)); @@ -82,7 +82,7 @@ TEST_CASE("wake up using ext1 when RTC_PERIPH is on (13 high)", "[deepsleep]") esp_deep_sleep_start(); } -TEST_CASE("wake up using ext1 when RTC_PERIPH is on (13 low)", "[deepsleep]") +TEST_CASE("wake up using ext1 when RTC_PERIPH is on (13 low)", "[deepsleep][ignore]") { ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); ESP_ERROR_CHECK(gpio_pullup_en(GPIO_NUM_13)); diff --git a/components/esp32/test/test_delay.c b/components/esp32/test/test_delay.c index 0b6c4aaf97..c34c3bda77 100644 --- a/components/esp32/test/test_delay.c +++ b/components/esp32/test/test_delay.c @@ -37,7 +37,7 @@ static void test_delay_task(void* p) vTaskDelete(NULL); } -TEST_CASE("ets_delay produces correct delay on both CPUs", "[delay]") +TEST_CASE("ets_delay produces correct delay on both CPUs", "[delay][ignore]") { int delay_ms = 50; const delay_test_arg_t args = { .delay_us = delay_ms * 1000, .method = 0 }; diff --git a/components/esp32/test/test_fastbus.c b/components/esp32/test/test_fastbus.c index 4ac5c55a88..2b58c725b0 100644 --- a/components/esp32/test/test_fastbus.c +++ b/components/esp32/test/test_fastbus.c @@ -96,7 +96,7 @@ static void tskTwo(void *pvParameters) // TODO: split this thing into separate orthogonal tests -TEST_CASE("Fast I/O bus test", "[hw]") +TEST_CASE("Fast I/O bus test", "[hw][ignore]") { int i; if ((REG_UART_BASE(0) >> 16) != 0x3ff4) { diff --git a/components/esp32/test/test_miniz.c b/components/esp32/test/test_miniz.c index 3453c859a9..d7d9dc33b6 100644 --- a/components/esp32/test/test_miniz.c +++ b/components/esp32/test/test_miniz.c @@ -7,7 +7,7 @@ #define DATASIZE (1024*64) -TEST_CASE("Test miniz compression/decompression", "[miniz]") +TEST_CASE("Test miniz compression/decompression", "[miniz][ignore]") { int x; char b; diff --git a/components/esp32/test/test_unal_dma.c b/components/esp32/test/test_unal_dma.c index 3726632a41..c05d0d0f36 100644 --- a/components/esp32/test/test_unal_dma.c +++ b/components/esp32/test/test_unal_dma.c @@ -183,7 +183,7 @@ int mymemcmp(char *a, char *b, int len) -TEST_CASE("Unaligned DMA test (needs I2S)", "[hw]") +TEST_CASE("Unaligned DMA test (needs I2S)", "[hw][ignore]") { int x; char src[2049], dest[2049]; diff --git a/components/espcoredump/espcoredump.py b/components/espcoredump/espcoredump.py index 1589a362b9..521f211c17 100755 --- a/components/espcoredump/espcoredump.py +++ b/components/espcoredump/espcoredump.py @@ -12,15 +12,15 @@ import array import errno import base64 +idf_path = os.getenv('IDF_PATH') +if idf_path: + sys.path.insert(0, os.path.join(idf_path, 'components', 'esptool_py', 'esptool')) + try: import esptool except ImportError: - idf_path = os.getenv('IDF_PATH') - if idf_path is None: - print "Esptool is not found! Install it or set proper $IDF_PATH in environment." - sys.exit(2) - sys.path.append('%s/components/esptool_py/esptool' % idf_path) - import esptool + print "Esptool is not found! Set proper $IDF_PATH in environment." + sys.exit(2) __version__ = "0.1-dev" diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index e249d14432..dfe8e1f428 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -29,7 +29,7 @@ endif ESPTOOL_ELF2IMAGE_OPTIONS := -ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_WRITE_FLASH_OPTIONS) +ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z,-u) $(ESPTOOL_WRITE_FLASH_OPTIONS) ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index fe69994270..e9e9179f6f 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit fe69994270e2a450aad3e94a409b58460b1a214f +Subproject commit e9e9179f6fc3f2ecfc568987d3224b5e53a05f06 diff --git a/components/ethernet/Kconfig b/components/ethernet/Kconfig index 0ea94eaafd..46e86cc60e 100644 --- a/components/ethernet/Kconfig +++ b/components/ethernet/Kconfig @@ -5,30 +5,48 @@ menuconfig ETHERNET Select this option to enable ethernet driver and show the submenu with ethernet features. config DMA_RX_BUF_NUM - int "DMA Rx Buf Num" - default 10 - depends on ETHERNET - help - Dma rx buf num ,can not be 0 . - -config DMA_TX_BUF_NUM - int "DMA Tx Buf Num" + int "Number of DMA RX buffers" + range 3 20 default 10 depends on ETHERNET help - Dma tx Buf num ,can not be 0. + 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_TX_BUF_NUM + int "Number of DMA RX buffers" + range 3 20 + default 10 + depends on ETHERNET + help + Number of DMA transmit buffers. Each buffer is 1600 bytes. + Buffers are allocated statically. + Larger number of buffers increases throughput. config EMAC_L2_TO_L3_RX_BUF_MODE - bool "L2 To L3 RX BUF COPY MODE" + bool "Enable copy between Layer2 and Layer3" default n depends on ETHERNET help - Receive Buf user copy mode or pointer mode. + 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. + + When Ethernet MAC doesn't have any unused buffers left, it will drop incomming + packets (flow control may help with this problem, to some extent). + + 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. + + If unsure, choose n. config EMAC_TASK_PRIORITY int "EMAC_TASK_PRIORITY" default 20 + range 3 22 depends on ETHERNET help - Emac task priority ,suggest 3 ~ 23. + Ethernet MAC task priority. diff --git a/components/ethernet/emac_common.h b/components/ethernet/emac_common.h index 957337d2a7..d68c20a056 100644 --- a/components/ethernet/emac_common.h +++ b/components/ethernet/emac_common.h @@ -75,6 +75,7 @@ struct emac_config_data { 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; }; enum emac_post_type { diff --git a/components/ethernet/emac_main.c b/components/ethernet/emac_main.c index 9446e8ee35..5479ec399e 100644 --- a/components/ethernet/emac_main.c +++ b/components/ethernet/emac_main.c @@ -216,8 +216,16 @@ static void emac_set_user_config_data(eth_config_t *config ) emac_config.emac_phy_check_init = config->phy_check_init; emac_config.emac_phy_get_speed_mode = config->phy_get_speed_mode; emac_config.emac_phy_get_duplex_mode = config->phy_get_duplex_mode; +#if DMA_RX_BUF_NUM > 9 emac_config.emac_flow_ctrl_enable = config->flow_ctrl_enable; +#else + if(config->flow_ctrl_enable == true) { + ESP_LOGE(TAG, "eth flow ctrl init err!!! Please run make menuconfig and make sure DMA_RX_BUF_NUM > 9 ."); + } + 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_power_enable = config->phy_power_enable; } static void emac_enable_intr() @@ -284,6 +292,11 @@ static esp_err_t emac_verify_args(void) ret = ESP_FAIL; } + if(emac_config.emac_phy_power_enable == NULL) { + ESP_LOGE(TAG, "phy power enable func is null"); + ret = ESP_FAIL; + } + return ret; } @@ -530,6 +543,10 @@ static void emac_check_phy_init(void) } else { REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED); } +#if CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE + 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 && emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) { emac_enable_flowctrl(); @@ -542,6 +559,7 @@ static void emac_check_phy_init(void) emac_disable_flowctrl(); emac_config.emac_flow_ctrl_partner_support = false; } +#endif emac_mac_enable_txrx(); } static void emac_process_link_updown(bool link_status) @@ -588,7 +606,7 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size) if (emac_config.emac_status != EMAC_RUNTIME_START || emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) { ESP_LOGI(TAG, "tx netif close"); ret = ERR_IF; - goto _exit; + return ret; } xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY ); @@ -931,6 +949,8 @@ esp_err_t esp_eth_init(eth_config_t *config) emac_set_user_config_data(config); } + emac_config.emac_phy_power_enable(true); + ret = emac_verify_args(); if (ret != ESP_OK) { diff --git a/components/ethernet/include/esp_eth.h b/components/ethernet/include/esp_eth.h index e36c3ebfe6..c2a3554b11 100644 --- a/components/ethernet/include/esp_eth.h +++ b/components/ethernet/include/esp_eth.h @@ -80,7 +80,7 @@ typedef void (*eth_phy_func)(void); typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb); typedef void (*eth_gpio_config_func)(void); typedef bool (*eth_phy_get_partner_pause_enable_func)(void); - +typedef void (*eth_phy_power_enable_func)(bool enable); /** * @brief ethernet configuration @@ -98,6 +98,7 @@ typedef struct { eth_gpio_config_func gpio_config; /*!< gpio config func */ bool flow_ctrl_enable; /*!< flag of flow ctrl enable */ eth_phy_get_partner_pause_enable_func phy_get_partner_pause_enable; /*!< get partner pause enable */ + eth_phy_power_enable_func phy_power_enable; /*!< enable or disable phy power */ } eth_config_t; diff --git a/components/fatfs/src/vfs_fat.c b/components/fatfs/src/vfs_fat.c index 4ef387b43b..73bed5eaa1 100644 --- a/components/fatfs/src/vfs_fat.c +++ b/components/fatfs/src/vfs_fat.c @@ -152,7 +152,7 @@ static int fat_mode_conv(int m) } if ((m & O_CREAT) && (m & O_EXCL)) { res |= FA_CREATE_NEW; - } else if (m & O_CREAT) { + } else if ((m & O_CREAT) && (m & O_TRUNC)) { res |= FA_CREATE_ALWAYS; } else if (m & O_APPEND) { res |= FA_OPEN_ALWAYS; diff --git a/components/fatfs/test/test_fatfs.c b/components/fatfs/test/test_fatfs.c index 9ee6606fb8..4f6482740c 100644 --- a/components/fatfs/test/test_fatfs.c +++ b/components/fatfs/test/test_fatfs.c @@ -52,7 +52,7 @@ static void create_file_with_text(const char* name, const char* text) TEST_ASSERT_EQUAL(0, fclose(f)); } -TEST_CASE("can create and write file on sd card", "[fatfs]") +TEST_CASE("can create and write file on sd card", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); @@ -69,7 +69,56 @@ TEST_CASE("can create and write file on sd card", "[fatfs]") HEAP_SIZE_CHECK(0); } -TEST_CASE("can read file on sd card", "[fatfs]") +TEST_CASE("overwrite and append file on sd card", "[fatfs][ignore]") +{ + HEAP_SIZE_CAPTURE(); + + sdmmc_host_t host = SDMMC_HOST_DEFAULT(); + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + .format_if_mount_failed = true, + .max_files = 5 + }; + TEST_ESP_OK(esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, NULL)); + + /* Create new file with 'aaaa' */ + const char *NAME = "/sdcard/hello.txt"; + create_file_with_text(NAME, "aaaa"); + + /* Append 'bbbb' to file */ + FILE *f_a = fopen(NAME, "a"); + TEST_ASSERT_NOT_NULL(f_a); + TEST_ASSERT_NOT_EQUAL(EOF, fputs("bbbb", f_a)); + TEST_ASSERT_EQUAL(0, fclose(f_a)); + + /* Read back 8 bytes from file, verify it's 'aaaabbbb' */ + char buf[10] = { 0 }; + FILE *f_r = fopen(NAME, "r"); + TEST_ASSERT_NOT_NULL(f_r); + TEST_ASSERT_EQUAL(8, fread(buf, 1, 8, f_r)); + TEST_ASSERT_EQUAL_STRING_LEN("aaaabbbb", buf, 8); + + /* Be sure we're at end of file */ + TEST_ASSERT_EQUAL(0, fread(buf, 1, 8, f_r)); + + TEST_ASSERT_EQUAL(0, fclose(f_r)); + + /* Overwrite file with 'cccc' */ + create_file_with_text(NAME, "cccc"); + + /* Verify file now only contains 'cccc' */ + f_r = fopen(NAME, "r"); + TEST_ASSERT_NOT_NULL(f_r); + bzero(buf, sizeof(buf)); + TEST_ASSERT_EQUAL(4, fread(buf, 1, 8, f_r)); // trying to read 8 bytes, only expecting 4 + TEST_ASSERT_EQUAL_STRING_LEN("cccc", buf, 4); + TEST_ASSERT_EQUAL(0, fclose(f_r)); + + TEST_ESP_OK(esp_vfs_fat_sdmmc_unmount()); + HEAP_SIZE_CHECK(0); +} + +TEST_CASE("can read file on sd card", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); @@ -134,7 +183,7 @@ static void speed_test(void* buf, size_t buf_size, size_t file_size, bool write) } -TEST_CASE("read speed test", "[fatfs]") +TEST_CASE("read speed test", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); @@ -151,7 +200,7 @@ TEST_CASE("read speed test", "[fatfs]") HEAP_SIZE_CHECK(0); } -TEST_CASE("write speed test", "[fatfs]") +TEST_CASE("write speed test", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); @@ -171,7 +220,7 @@ TEST_CASE("write speed test", "[fatfs]") HEAP_SIZE_CHECK(0); } -TEST_CASE("can lseek", "[fatfs]") +TEST_CASE("can lseek", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); @@ -208,7 +257,7 @@ TEST_CASE("can lseek", "[fatfs]") HEAP_SIZE_CHECK(0); } -TEST_CASE("stat returns correct values", "[fatfs]") +TEST_CASE("stat returns correct values", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); @@ -249,7 +298,7 @@ TEST_CASE("stat returns correct values", "[fatfs]") HEAP_SIZE_CHECK(0); } -TEST_CASE("unlink removes a file", "[fatfs]") +TEST_CASE("unlink removes a file", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); @@ -271,7 +320,7 @@ TEST_CASE("unlink removes a file", "[fatfs]") HEAP_SIZE_CHECK(0); } -TEST_CASE("link copies a file, rename moves a file", "[fatfs]") +TEST_CASE("link copies a file, rename moves a file", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); @@ -373,7 +422,7 @@ done: } -TEST_CASE("multiple tasks can use same volume", "[fatfs]") +TEST_CASE("multiple tasks can use same volume", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); @@ -434,7 +483,7 @@ TEST_CASE("multiple tasks can use same volume", "[fatfs]") HEAP_SIZE_CHECK(0); } -TEST_CASE("can create and remove directories", "[fatfs]") +TEST_CASE("can create and remove directories", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); @@ -470,7 +519,7 @@ TEST_CASE("can create and remove directories", "[fatfs]") HEAP_SIZE_CHECK(0); } -TEST_CASE("opendir, readdir, rewinddir, seekdir work as expected", "[fatfs]") +TEST_CASE("opendir, readdir, rewinddir, seekdir work as expected", "[fatfs][ignore]") { HEAP_SIZE_CAPTURE(); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 15178539b4..ee2b289ef8 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -30,11 +30,6 @@ config FREERTOS_CORETIMER_1 help Select this to use timer 1 -config FREERTOS_CORETIMER_2 - bool "Timer 2 (int 16, level 5)" - help - Select this to use timer 2 - endchoice config FREERTOS_HZ diff --git a/components/freertos/include/freertos/FreeRTOSConfig.h b/components/freertos/include/freertos/FreeRTOSConfig.h index b2fc077bc3..9deb9f4b5e 100644 --- a/components/freertos/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/include/freertos/FreeRTOSConfig.h @@ -90,10 +90,6 @@ #define XT_TIMER_INDEX 0 #elif CONFIG_FREERTOS_CORETIMER_1 #define XT_TIMER_INDEX 1 -#elif CONFIG_FREERTOS_CORETIMER_2 -#define XT_TIMER_INDEX 2 -#elif CONFIG_FREERTOS_CORETIMER_3 -#define XT_TIMER_INDEX 3 #endif #define configNUM_THREAD_LOCAL_STORAGE_POINTERS CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS diff --git a/components/freertos/include/freertos/portable.h b/components/freertos/include/freertos/portable.h index b05755da40..0c10ac36eb 100644 --- a/components/freertos/include/freertos/portable.h +++ b/components/freertos/include/freertos/portable.h @@ -216,6 +216,9 @@ static inline uint32_t xPortGetCoreID() { return id; } +/* Get tick rate per second */ +uint32_t xPortGetTickRateHz(void); + #ifdef __cplusplus } #endif diff --git a/components/freertos/port.c b/components/freertos/port.c index c778950d6d..3c26edfabf 100644 --- a/components/freertos/port.c +++ b/components/freertos/port.c @@ -406,7 +406,9 @@ void vPortSetStackWatchpoint( void* pxStackStart ) { esp_set_watchpoint(1, (char*)addr, 32, ESP_WATCHPOINT_STORE); } - +uint32_t xPortGetTickRateHz(void) { + return (uint32_t)configTICK_RATE_HZ; +} diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 6caabaa38e..0804bb3eb5 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -632,7 +632,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode */ void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority ) { - TCB_t *curTCB = xTaskGetCurrentTaskHandle(); + TCB_t *curTCB = pxCurrentTCB[xCoreID]; BaseType_t i; if (xCoreID != tskNO_AFFINITY) { @@ -1056,11 +1056,15 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode taskENTER_CRITICAL(&xTaskQueueMutex); { uxCurrentNumberOfTasks++; - if( pxCurrentTCB[ xPortGetCoreID() ] == NULL ) + //If the task has no affinity and nothing is scheduled on this core, just throw it this core. + //If it has affinity, throw it on the core that needs it if nothing is already scheduled there. + BaseType_t xMyCore = xCoreID; + if ( xMyCore == tskNO_AFFINITY) xMyCore = xPortGetCoreID(); + if( pxCurrentTCB[ xMyCore ] == NULL ) { /* There are no other tasks, or all the other tasks are in the suspended state - make this the current task. */ - pxCurrentTCB[ xPortGetCoreID() ] = pxNewTCB; + pxCurrentTCB[ xMyCore ] = pxNewTCB; if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) { @@ -1121,12 +1125,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode portSETUP_TCB( pxNewTCB ); } - curTCB = pxCurrentTCB[ xPortGetCoreID() ]; + taskEXIT_CRITICAL(&xTaskQueueMutex); if( xSchedulerRunning != pdFALSE ) { taskENTER_CRITICAL(&xTaskQueueMutex); + curTCB = pxCurrentTCB[ xPortGetCoreID() ]; /* Scheduler is running. If the created task is of a higher priority than an executing task then it should run now. ToDo: This only works for the current core. If a task is scheduled on an other processor, @@ -1141,7 +1146,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode */ if( tskCAN_RUN_HERE( xCoreID ) && curTCB->uxPriority < pxNewTCB->uxPriority ) { - taskYIELD_IF_USING_PREEMPTION(); + taskYIELD_IF_USING_PREEMPTION_MUX(&xTaskQueueMutex); } else if( xCoreID != xPortGetCoreID() ) { taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority); @@ -2381,26 +2386,15 @@ BaseType_t xSwitchRequired = pdFALSE; switch, even when this routine (running on core 0) unblocks a bunch of high-priority tasks... this is less than optimal -- JD. */ if ( xPortGetCoreID()!=0 ) { + #if ( configUSE_TICK_HOOK == 1 ) + vApplicationTickHook(); + #endif /* configUSE_TICK_HOOK */ + esp_vApplicationTickHook(); + /* We can't really calculate what we need, that's done on core 0... just assume we need a switch. ToDo: Make this more intelligent? -- JD */ - { - /* Guard against the tick hook being called when the pended tick - count is being unwound (when the scheduler is being unlocked). */ - if( ( uxSchedulerSuspended[ xPortGetCoreID() ] != ( UBaseType_t ) pdFALSE ) || uxPendedTicks == ( UBaseType_t ) 0U ) - { - #if ( configUSE_TICK_HOOK == 1 ) - vApplicationTickHook(); - #endif /* configUSE_TICK_HOOK */ - esp_vApplicationTickHook(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - return pdTRUE; } @@ -2670,11 +2664,13 @@ BaseType_t xSwitchRequired = pdFALSE; void vTaskSwitchContext( void ) { - tskTCB * pxTCB; - //This can be called both from IRQ as well as normal context, so we can't - //use taskENTER_CRITICAL() here. Instead, save the irq status and disable - //IRQs, so we can use taskENTER_CRITICAL_ISR and friends. + //Note: This can be called from interrupt context as well as from non-interrupt context (voluntary yield). The + //taskENTER_CRITICAL/taskEXIT_CRITICAL is modified to work in both scenarios for the ESP32, so we can freely use + //them here. However, in case of a voluntary yield, a nonvoluntary yield can still happen *during* the voluntary + //yield. Disabling interrupts using portENTER_CRITICAL_NESTED puts a stop to this and makes the rest of the code a + //bit neater. int irqstate=portENTER_CRITICAL_NESTED(); + tskTCB * pxTCB; if( uxSchedulerSuspended[ xPortGetCoreID() ] != ( UBaseType_t ) pdFALSE ) { /* The scheduler is currently suspended - do not allow a context @@ -3023,9 +3019,14 @@ BaseType_t xReturn; This function assumes that a check has already been made to ensure that pxEventList is not empty. */ - pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); - configASSERT( pxUnblockedTCB ); - ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); + if ( ( listLIST_IS_EMPTY( pxEventList ) ) == pdFALSE ) { + pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + configASSERT( pxUnblockedTCB ); + ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); + } else { + taskEXIT_CRITICAL_ISR(&xTaskQueueMutex); + return pdFALSE; + } if( uxSchedulerSuspended[ xPortGetCoreID() ] == ( UBaseType_t ) pdFALSE ) { @@ -3036,9 +3037,7 @@ BaseType_t xReturn; { /* The delayed and ready lists cannot be accessed, so hold this task pending until the scheduler is resumed. */ - taskENTER_CRITICAL(&xTaskQueueMutex); vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxUnblockedTCB->xEventListItem ) ); - taskEXIT_CRITICAL(&xTaskQueueMutex); } if ( tskCAN_RUN_HERE(pxUnblockedTCB->xCoreID) && pxUnblockedTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) diff --git a/components/freertos/test/test_freertos.c b/components/freertos/test/test_freertos.c index ced375279b..2eb0c9391b 100644 --- a/components/freertos/test/test_freertos.c +++ b/components/freertos/test/test_freertos.c @@ -187,7 +187,7 @@ static void uartRxInit(xQueueHandle q) } // TODO: split this thing into separate orthogonal tests -TEST_CASE("Bunch of FreeRTOS tests", "[freertos]") +TEST_CASE("Bunch of FreeRTOS tests", "[freertos][ignore]") { char *tst; TaskHandle_t th[12]; diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index b17e127c28..32dee2d201 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -38,7 +38,7 @@ static void task_event_group_call_response(void *param) vTaskDelete(NULL); } -TEST_CASE("FreeRTOS Event Groups", "[freertos]") +TEST_CASE("FreeRTOS Event Groups", "[freertos][ignore]") { eg = xEventGroupCreate(); @@ -89,7 +89,7 @@ static void task_test_sync(void *param) vTaskDelete(NULL); } -TEST_CASE("FreeRTOS Event Group Sync", "[freertos]") +TEST_CASE("FreeRTOS Event Group Sync", "[freertos][ignore]") { eg = xEventGroupCreate(); diff --git a/components/freertos/test/test_freertos_task_delete.c b/components/freertos/test/test_freertos_task_delete.c index 3101db2564..d8cc2755ed 100644 --- a/components/freertos/test/test_freertos_task_delete.c +++ b/components/freertos/test/test_freertos_task_delete.c @@ -13,7 +13,7 @@ static void task_delete_self(void *param) vTaskDelete(NULL); } -TEST_CASE("FreeRTOS Delete Tasks", "[freertos]") +TEST_CASE("FreeRTOS Delete Tasks", "[freertos][ignore]") { xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0); xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0); diff --git a/components/freertos/test/test_panic.c b/components/freertos/test/test_panic.c index 782b7a5642..6297d80c0e 100644 --- a/components/freertos/test/test_panic.c +++ b/components/freertos/test/test_panic.c @@ -17,7 +17,7 @@ #include "soc/io_mux_reg.h" -TEST_CASE("Panic handler", "[freertos]") +TEST_CASE("Panic handler", "[freertos][ignore]") { volatile int *i; i = (volatile int *)0x0; diff --git a/components/freertos/test/test_ringbuf.c b/components/freertos/test/test_ringbuf.c index 7d3c8788c9..8f8328532d 100644 --- a/components/freertos/test/test_ringbuf.c +++ b/components/freertos/test/test_ringbuf.c @@ -185,12 +185,12 @@ static void testRingbuffer(int type) } // TODO: split this thing into separate orthogonal tests -TEST_CASE("FreeRTOS ringbuffer test, no splitting items", "[freertos]") +TEST_CASE("FreeRTOS ringbuffer test, no splitting items", "[freertos][ignore]") { testRingbuffer(0); } -TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items", "[freertos]") +TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items", "[freertos][ignore]") { testRingbuffer(1); } diff --git a/components/idf_test/unit_test/CIConfigs/UT_Function_SYS_01.yml b/components/idf_test/unit_test/CIConfigs/UT_Function_SYS_01.yml deleted file mode 100644 index f4755dfec4..0000000000 --- a/components/idf_test/unit_test/CIConfigs/UT_Function_SYS_01.yml +++ /dev/null @@ -1,7 +0,0 @@ -Config: {execute count: 1, execute order: in order} -DUT: [UT1] -Filter: -- Add: - ID: [SYS_OS_0102, SYS_MISC_0102, SYS_MISC_0107, SYS_MISC_0106, SYS_MISC_0109, - SYS_MISC_0108, SYS_MISC_0112, SYS_MISC_0113, SYS_MISC_0110, SYS_MISC_0111, SYS_LIB_0103, - SYS_LIB_0102, SYS_LIB_0101, SYS_LIB_0106, SYS_LIB_0105, SYS_LIB_0104] diff --git a/components/idf_test/unit_test/TestCaseAll.yml b/components/idf_test/unit_test/TestCaseAll.yml deleted file mode 100644 index 4e5c01f219..0000000000 --- a/components/idf_test/unit_test/TestCaseAll.yml +++ /dev/null @@ -1,461 +0,0 @@ -test cases: -- CI ready: 'Yes' - ID: SYS_LIB_0101 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "check if ROM or Flash is used for functions" - - [dummy] - comment: check if ROM or Flash is used for functions - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run lib test - sub module: Std Lib - summary: lib unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: lib - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_LIB_0102 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test time functions" - - [dummy] - comment: test time functions - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run lib test - sub module: Std Lib - summary: lib unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: lib - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_LIB_0103 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test sscanf function" - - [dummy] - comment: test sscanf function - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run lib test - sub module: Std Lib - summary: lib unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: lib - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_LIB_0104 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test sprintf function" - - [dummy] - comment: test sprintf function - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run lib test - sub module: Std Lib - summary: lib unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: lib - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_LIB_0105 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test atoX functions" - - [dummy] - comment: test atoX functions - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run lib test - sub module: Std Lib - summary: lib unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: lib - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_LIB_0106 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test ctype functions" - - [dummy] - comment: test ctype functions - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run lib test - sub module: Std Lib - summary: lib unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: lib - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0102 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "mbedtls MPI self-tests" - - [dummy] - comment: mbedtls MPI self-tests - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run bignum test - sub module: Misc - summary: bignum unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: bignum - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0103 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test AES thread safety" - - [dummy] - comment: test AES thread safety - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run hwcrypto test - sub module: Misc - summary: hwcrypto unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: hwcrypto - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0104 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test AES acceleration" - - [dummy] - comment: test AES acceleration - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run hwcrypto test - sub module: Misc - summary: hwcrypto unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: hwcrypto - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0105 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test SHA thread safety" - - [dummy] - comment: test SHA thread safety - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run hwcrypto test - sub module: Misc - summary: hwcrypto unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: hwcrypto - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0106 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "context switch saves FP registers" - - [dummy] - comment: context switch saves FP registers - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run fp test - sub module: Misc - summary: fp unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: fp - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0107 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test FP sqrt" - - [dummy] - comment: test FP sqrt - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run fp test - sub module: Misc - summary: fp unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: fp - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0108 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test FP div" - - [dummy] - comment: test FP div - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run fp test - sub module: Misc - summary: fp unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: fp - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0109 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test FP mul" - - [dummy] - comment: test FP mul - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run fp test - sub module: Misc - summary: fp unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: fp - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0110 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test FP add" - - [dummy] - comment: test FP add - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run fp test - sub module: Misc - summary: fp unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: fp - version: v1 (2016-10-26) -- CI ready: 'Yes' - ID: SYS_MISC_0111 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "Test JPEG decompression library" - - [dummy] - comment: Test JPEG decompression library - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run JPEG decompression test - sub module: Misc - summary: JPEG decompression library unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: tjpgd - version: v1 (2016-10-31) -- CI ready: 'Yes' - ID: SYS_MISC_0112 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "mbedtls AES self-tests" - - [dummy] - comment: mbedtls AES self-tests - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run mbedtls AES self-tests - sub module: Misc - summary: mbedtls AES unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: mbedtls AES - version: v1 (2016-10-31) -- CI ready: 'Yes' - ID: SYS_MISC_0113 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "mbedtls SHA self-tests" - - [dummy] - comment: mbedtls SHA self-tests - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run mbedtls SHA self-tests - sub module: Misc - summary: mbedtls SHA unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: mbedtls SHA - version: v1 (2016-10-31) -- CI ready: 'Yes' - ID: SYS_MISC_0115 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "test SHA acceleration" - - [dummy] - comment: test SHA acceleration - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run SHA acceleration test - sub module: Misc - summary: SHA acceleration unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: SHA acceleration - version: v1 (2016-10-31) -- CI ready: 'Yes' - ID: SYS_OS_0102 - SDK: ESP32_IDF - Test App: UT - auto test: 'Yes' - category: Function - cmd set: - - IDFUnitTest/UnitTest - - - test_case = "Freertos TLS delete cb" - - [dummy] - comment: Freertos TLS delete cb - execution time: 0 - expected result: 1. set succeed - initial condition: UTINIT1 - level: Unit - module: System - steps: 1. run Freertos TLS delete cb test - sub module: OS - summary: Freertos TLS delete cb unit test - test environment: UT_T1_1 - test point 1: basic function - test point 2: Freertos TLS delete cb - version: v1 (2016-10-31) diff --git a/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/UnitTest.py b/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/UnitTest.py index bfc8edeaa9..1625e4e36c 100644 --- a/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/UnitTest.py +++ b/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/UnitTest.py @@ -9,41 +9,40 @@ class UnitTest(PerformanceTCBase.PerformanceTCBase): def __init__(self, name, test_env, cmd_set, timeout=30, log_path=TCActionBase.LOG_PATH): PerformanceTCBase.PerformanceTCBase.__init__(self, name, test_env, cmd_set=cmd_set, timeout=timeout, log_path=log_path) - + self.test_case = None self.test_timeout = 20 - + # load param from excel for i in range(1, len(cmd_set)): if cmd_set[i][0] != "dummy": - cmd_string = "self." + cmd_set[i][0] + cmd_string = "self.test_case = " + "\"" + cmd_set[i][0] + "\"" exec cmd_string self.result_cntx = TCActionBase.ResultCheckContext(self, test_env, self.tc_name) pass def send_commands(self): self.flush_data("UT1") - + try: - # add case select by name mark " before case name - self.serial_write_line("UT1", "\"" + self.test_case) + self.serial_write_line("UT1", "\"" + self.test_case + "\"") data = "" for _ in range(self.timeout): time.sleep(1) #wait for test to run before reading result data += self.serial_read_data("UT1") - if re.search('[^0] Tests 0 F', data): #check that number of tests run != 0 and number of tests failed == 0 + if re.search('[^0].* Tests 0 F', data): #check that number of tests run != 0 and number of tests failed == 0 self.set_result("Succeed") break else: self.set_result("Fail") - + except StandardError,e: NativeLog.add_exception_log(e) - + def execute(self): TCActionBase.TCActionBase.execute(self) self.send_commands() - + def main(): pass diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 760e035c8c..0070ef4668 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -47,27 +47,48 @@ config LWIP_SO_RCVBUF Enabling this option allows checking for available data on a netconn. config LWIP_DHCP_MAX_NTP_SERVERS - int "Maximum number of NTP servers" - default 1 - range 1 16 - help - Set maxumum number of NTP servers used by LwIP SNTP module. - First argument of sntp_setserver/sntp_setservername functions - is limited to this value. + int "Maximum number of NTP servers" + default 1 + range 1 16 + help + Set maximum number of NTP servers used by LwIP SNTP module. + First argument of sntp_setserver/sntp_setservername functions + is limited to this value. config LWIP_IP_FRAG bool "Enable fragment outgoing IP packets" default 0 - help + help Enabling this option allows fragmenting outgoing IP packets if their size exceeds MTU. config LWIP_IP_REASSEMBLY bool "Enable reassembly incoming fragmented IP packets" default 0 - help + help Enabling this option allows reassemblying incoming fragmented IP packets. +config TCP_MAXRTX + int "Maximum number of retransmissions of data segments" + default 12 + range 3 12 + help + Set maximum number of retransmissions of data segments. + +config TCP_SYNMAXRTX + int "Maximum number of retransmissions of SYN segments" + default 6 + range 3 12 + help + Set maximum number of retransmissions of SYN segments. + +config LWIP_DHCP_DOES_ARP_CHECK + bool "Enable an ARP check on the offered address" + default 1 + help + Enabling this option allows check if the offered IP address is not already + in use by another host on the network. + endmenu diff --git a/components/lwip/api/api_lib.c b/components/lwip/api/api_lib.c index 087115f0b9..e5c247f0bc 100755 --- a/components/lwip/api/api_lib.c +++ b/components/lwip/api/api_lib.c @@ -880,10 +880,11 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr) { API_VAR_DECLARE(struct dns_api_msg, msg); + err_t localerr; #if !LWIP_MPU_COMPATIBLE sys_sem_t sem; #endif /* LWIP_MPU_COMPATIBLE */ - err_t err; + err_t err = ERR_OK; LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); @@ -918,14 +919,14 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr) } #endif /* LWIP_NETCONN_SEM_PER_THREAD */ - err = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); - if (err != ERR_OK) { + localerr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); + if (localerr != ERR_OK) { #if !LWIP_NETCONN_SEM_PER_THREAD sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ API_VAR_FREE(MEMP_DNS_API_MSG, msg); - return err; + return localerr; } sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem)); diff --git a/components/lwip/api/tcpip.c b/components/lwip/api/tcpip.c index f3422af706..8374c429cd 100755 --- a/components/lwip/api/tcpip.c +++ b/components/lwip/api/tcpip.c @@ -501,8 +501,8 @@ tcpip_init(tcpip_init_done_fn initfunc, void *arg) sys_thread_t xLwipTaskHandle = sys_thread_new(TCPIP_THREAD_NAME , tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); - printf("tcpip_task_hdlxxx : %x, prio:%d,stack:%d\n", - (u32_t)xLwipTaskHandle,TCPIP_THREAD_PRIO,TCPIP_THREAD_STACKSIZE); + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_task_hdlxxx : %x, prio:%d,stack:%d\n", + (u32_t)xLwipTaskHandle,TCPIP_THREAD_PRIO,TCPIP_THREAD_STACKSIZE)); } diff --git a/components/lwip/core/ipv4/dhcp.c b/components/lwip/core/ipv4/dhcp.c index 887af91fe3..86336d4f7b 100755 --- a/components/lwip/core/ipv4/dhcp.c +++ b/components/lwip/core/ipv4/dhcp.c @@ -1029,7 +1029,12 @@ dhcp_discover(struct netif *netif) autoip_start(netif); } #endif /* LWIP_DHCP_AUTOIP_COOP */ - msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; + + /* Since for embedded devices it's not that hard to miss a discover packet, so lower + * the discover retry backoff time from (2,4,8,16,32,60,60)s to (500m,1,2,4,8,15,15)s. + * Original msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; + */ + msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 250; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); return result; diff --git a/components/lwip/include/lwip/port/lwipopts.h b/components/lwip/include/lwip/port/lwipopts.h index 6d1dfbd497..dc82649479 100644 --- a/components/lwip/include/lwip/port/lwipopts.h +++ b/components/lwip/include/lwip/port/lwipopts.h @@ -206,6 +206,11 @@ #define DHCP_MAXRTX 0 +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#define DHCP_DOES_ARP_CHECK CONFIG_LWIP_DHCP_DOES_ARP_CHECK + /* ------------------------------------ ---------- AUTOIP options ---------- @@ -288,12 +293,12 @@ /** * TCP_MAXRTX: Maximum number of retransmissions of data segments. */ -#define TCP_MAXRTX 12 //(*(volatile uint32*)0x600011E8) +#define TCP_MAXRTX CONFIG_TCP_MAXRTX /** * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. */ -#define TCP_SYNMAXRTX 6 //(*(volatile uint32*)0x600011E4) +#define TCP_SYNMAXRTX CONFIG_TCP_SYNMAXRTX /** * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. diff --git a/components/mbedtls/test/test_mbedtls_sha.c b/components/mbedtls/test/test_mbedtls_sha.c index b18169827b..2ec3bc3477 100644 --- a/components/mbedtls/test/test_mbedtls_sha.c +++ b/components/mbedtls/test/test_mbedtls_sha.c @@ -116,7 +116,7 @@ static void tskRunSHA256Test(void *pvParameters) vTaskDelete(NULL); } -TEST_CASE("mbedtls SHA multithreading", "[mbedtls]") +TEST_CASE("mbedtls SHA multithreading", "[mbedtls][ignore]") { done_sem = xSemaphoreCreateCounting(4, 0); xTaskCreate(tskRunSHA1Test, "SHA1Task1", 8192, NULL, 3, NULL); diff --git a/components/newlib/include/assert.h b/components/newlib/include/assert.h index 91bb040cab..df46c030b2 100644 --- a/components/newlib/include/assert.h +++ b/components/newlib/include/assert.h @@ -11,7 +11,7 @@ extern "C" { #undef assert #ifdef NDEBUG /* required by ANSI standard */ -# define assert(__e) ((void)0) +# define assert(__e) ((void) sizeof(__e)) #else # define assert(__e) ((__e) ? (void)0 : __assert_func (__FILE__, __LINE__, \ __ASSERT_FUNC, #__e)) diff --git a/components/newlib/test/test_newlib.c b/components/newlib/test/test_newlib.c index 1d2a4bf09f..3627850209 100644 --- a/components/newlib/test/test_newlib.c +++ b/components/newlib/test/test_newlib.c @@ -19,7 +19,7 @@ TEST_CASE("test ctype functions", "[newlib]") TEST_ASSERT_FALSE( isspace('0') || isspace('9') || isspace(')') || isspace('A') || isspace('*') || isspace('\x81') || isspace('a')); } -TEST_CASE("test atoX functions", "[newlib]") +TEST_CASE("test atoX functions", "[newlib][ignore]") { TEST_ASSERT_EQUAL_INT(-2147483648, atoi("-2147483648")); TEST_ASSERT_EQUAL_INT(2147483647, atoi("2147483647")); @@ -153,7 +153,7 @@ TEST_CASE("test 64bit int formats", "[newlib]") TEST_ASSERT_EQUAL(val, sval); } #else -TEST_CASE("test 64bit int formats", "[newlib]") +TEST_CASE("test 64bit int formats", "[newlib][ignore]") { char* res = NULL; const uint64_t val = 123456789012LL; diff --git a/components/newlib/test/test_time.c b/components/newlib/test/test_time.c new file mode 100644 index 0000000000..a230a220bc --- /dev/null +++ b/components/newlib/test/test_time.c @@ -0,0 +1,50 @@ +#include +#include +#include "unity.h" +#include "driver/adc.h" +#include +#include +#include "soc/rtc_cntl_reg.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "sdkconfig.h" + + +// https://github.com/espressif/arduino-esp32/issues/120 +TEST_CASE("Reading RTC registers on APP CPU doesn't affect clock", "[newlib]") +{ + // This runs on APP CPU: + void time_adc_test_task(void* arg) + { + for (int i = 0; i < 200000; ++i) { + // wait for 20us, reading one of RTC registers + uint32_t ccount = xthal_get_ccount(); + while (xthal_get_ccount() - ccount < 20 * CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) { + volatile uint32_t val = REG_READ(RTC_CNTL_STATE0_REG); + (void) val; + } + } + SemaphoreHandle_t * p_done = (SemaphoreHandle_t *) arg; + xSemaphoreGive(*p_done); + vTaskDelay(1); + vTaskDelete(NULL); + } + + SemaphoreHandle_t done = xSemaphoreCreateBinary(); + xTaskCreatePinnedToCore(&time_adc_test_task, "time_adc", 4096, &done, 5, NULL, 1); + + // This runs on PRO CPU: + for (int i = 0; i < 4; ++i) { + struct timeval tv_start; + gettimeofday(&tv_start, NULL); + vTaskDelay(1000/portTICK_PERIOD_MS); + struct timeval tv_stop; + gettimeofday(&tv_stop, NULL); + float time_sec = tv_stop.tv_sec - tv_start.tv_sec + 1e-6f * (tv_stop.tv_usec - tv_start.tv_usec); + printf("(0) time taken: %f sec\n", time_sec); + TEST_ASSERT_TRUE(fabs(time_sec - 1.0f) < 0.1); + } + TEST_ASSERT_TRUE(xSemaphoreTake(done, 5000 / portTICK_RATE_MS)); +} + diff --git a/components/newlib/time.c b/components/newlib/time.c index c9fa72eeee..7595ab82b8 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -83,12 +83,17 @@ static volatile uint64_t s_microseconds = 0; static void IRAM_ATTR frc_timer_isr() { + // Write to FRC_TIMER_INT_REG may not take effect in some cases (root cause TBD) + // This extra write works around this issue. + // FRC_TIMER_LOAD_REG(0) is used here, but any other DPORT register address can also be used. + WRITE_PERI_REG(FRC_TIMER_LOAD_REG(0), FRC_TIMER_LOAD_VALUE(0)); WRITE_PERI_REG(FRC_TIMER_INT_REG(0), FRC_TIMER_INT_CLR); s_microseconds += FRC1_ISR_PERIOD_US; } #endif // WITH_FRC1 +#if defined(WITH_RTC) || defined(WITH_FRC1) static void set_boot_time(uint64_t time_us) { _lock_acquire(&s_boot_time_lock); @@ -113,6 +118,7 @@ static uint64_t get_boot_time() _lock_release(&s_boot_time_lock); return result; } +#endif //defined(WITH_RTC) || defined(WITH_FRC1) void esp_setup_time_syscalls() { diff --git a/components/nvs_flash/src/nvs_pagemanager.cpp b/components/nvs_flash/src/nvs_pagemanager.cpp index f4d02a7d40..768b30667a 100644 --- a/components/nvs_flash/src/nvs_pagemanager.cpp +++ b/components/nvs_flash/src/nvs_pagemanager.cpp @@ -163,8 +163,10 @@ esp_err_t PageManager::requestNewPage() return err; } +#ifndef NDEBUG assert(usedEntries == newPage->getUsedEntryCount()); - +#endif + mPageList.erase(maxErasedItemsPageIt); mFreePageList.push_back(erasedPage); diff --git a/components/openssl/Kconfig b/components/openssl/Kconfig new file mode 100644 index 0000000000..7ade98c459 --- /dev/null +++ b/components/openssl/Kconfig @@ -0,0 +1,70 @@ +menu "OpenSSL" + +config OPENSSL_DEBUG + bool "Enable OpenSSL debugging" + default n + help + Enable OpenSSL debugging function. + + If the option is enabled, "SSL_DEBUG" works. + +config OPENSSL_DEBUG_LEVEL + int "OpenSSL debugging level" + default 0 + range 0 255 + depends on OPENSSL_DEBUG + help + OpenSSL debugging level. + + Only function whose debugging level is higher than "OPENSSL_DEBUG_LEVEL" works. + + For example: + If OPENSSL_DEBUG_LEVEL = 2, you use function "SSL_DEBUG(1, "malloc failed")". Because 1 < 2, it will not print. + +config OPENSSL_LOWLEVEL_DEBUG + bool "Enable OpenSSL low-level module debugging" + default n + depends on OPENSSL_DEBUG + select MBEDTLS_DEBUG + help + If the option is enabled, low-level module debugging function of OpenSSL is enabled, e.g. mbedtls internal debugging function. + +choice OPENSSL_ASSERT + prompt "Select OpenSSL assert function" + default CONFIG_OPENSSL_ASSERT_EXIT + help + OpenSSL function needs "assert" function to check if input parameters are valid. + + If you want to use assert debugging function, "OPENSSL_DEBUG" should be enabled. + +config OPENSSL_ASSERT_DO_NOTHING + bool "Do nothing" + help + Do nothing and "SSL_ASSERT" does not work. + +config OPENSSL_ASSERT_EXIT + bool "Check and exit" + help + Enable assert exiting, it will check and return error code. + +config OPENSSL_ASSERT_DEBUG + bool "Show debugging message" + depends on OPENSSL_DEBUG + help + Enable assert debugging, it will check and show debugging message. + +config OPENSSL_ASSERT_DEBUG_EXIT + bool "Show debugging message and exit" + depends on OPENSSL_DEBUG + help + Enable assert debugging and exiting, it will check, show debugging message and return error code. + +config OPENSSL_ASSERT_DEBUG_BLOCK + bool "Show debugging message and block" + depends on OPENSSL_DEBUG + help + Enable assert debugging and blocking, it will check, show debugging message and block by "while (1);". + +endchoice + +endmenu diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index b4c0754637..12ba25f99d 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -22,72 +22,170 @@ extern "C" { #endif -#ifndef SSL_DEBUG_ENBALE -#define SSL_DEBUG_ENBALE 0 -#endif - -#ifndef SSL_DEBUG_LEVEL -#define SSL_DEBUG_LEVEL 0 -#endif - -#ifndef SSL_ASSERT_ENABLE -#define SSL_ASSERT_ENABLE 0 -#endif - -#ifndef SSL_DEBUG_LOCATION_ENABLE -#define SSL_DEBUG_LOCATION_ENABLE 0 -#endif - -#if SSL_DEBUG_ENBALE - #if !defined(SSL_PRINT_LOG) || !defined(SSL_ERROR_LOG) || !defined(SSL_LOCAL_LOG) - #include "stdio.h" - extern int printf(const char *fmt, ...); - #ifndef SSL_PRINT_LOG - #define SSL_PRINT_LOG printf - #endif - #ifndef SSL_ERROR_LOG - #define SSL_ERROR_LOG printf - #endif - #ifndef SSL_LOCAL_LOG - #define SSL_LOCAL_LOG printf - #endif - #endif +#ifdef CONFIG_OPENSSL_DEBUG_LEVEL + #define SSL_DEBUG_LEVEL CONFIG_OPENSSL_DEBUG_LEVEL #else - #ifdef SSL_PRINT_LOG - #undef SSL_PRINT_LOG - #endif - #define SSL_PRINT_LOG(...) - - #ifdef SSL_ERROR_LOG - #undef SSL_ERROR_LOG - #endif - #define SSL_ERROR_LOG(...) - #ifdef SSL_LOCAL_LOG - #undef SSL_LOCAL_LOG - #endif - #define SSL_LOCAL_LOG(...) + #define SSL_DEBUG_LEVEL 0 #endif -#if SSL_DEBUG_LOCATION_ENABLE - #define SSL_DEBUG_LOCATION() SSL_LOCAL_LOG("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__) +#define SSL_DEBUG_ON (SSL_DEBUG_LEVEL + 1) +#define SSL_DEBUG_OFF (SSL_DEBUG_LEVEL - 1) + +#ifdef CONFIG_OPENSSL_DEBUG + #ifndef SSL_DEBUG_LOG + #error "SSL_DEBUG_LOG is not defined" + #endif + + #ifndef SSL_DEBUG_FL + #define SSL_DEBUG_FL "\n" + #endif + + #define SSL_SHOW_LOCATION() \ + SSL_DEBUG_LOG("SSL assert : %s %d\n", \ + __FILE__, __LINE__) + + #define SSL_DEBUG(level, fmt, ...) \ + { \ + if (level > SSL_DEBUG_LEVEL) { \ + SSL_DEBUG_LOG(fmt SSL_DEBUG_FL, ##__VA_ARGS__); \ + } \ + } +#else /* CONFIG_OPENSSL_DEBUG */ + #define SSL_SHOW_LOCATION() + + #define SSL_DEBUG(level, fmt, ...) +#endif /* CONFIG_OPENSSL_DEBUG */ + +/** + * OpenSSL assert function + * + * if select "CONFIG_OPENSSL_ASSERT_DEBUG", SSL_ASSERT* will show error file name and line + * if select "CONFIG_OPENSSL_ASSERT_EXIT", SSL_ASSERT* will just return error code. + * if select "CONFIG_OPENSSL_ASSERT_DEBUG_EXIT" SSL_ASSERT* will show error file name and line, + * then return error code. + * if select "CONFIG_OPENSSL_ASSERT_DEBUG_BLOCK", SSL_ASSERT* will show error file name and line, + * then block here with "while (1)" + * + * SSL_ASSERT1 may will return "-1", so function's return argument is integer. + * SSL_ASSERT2 may will return "NULL", so function's return argument is a point. + * SSL_ASSERT2 may will return nothing, so function's return argument is "void". + */ +#if defined(CONFIG_OPENSSL_ASSERT_DEBUG) + #define SSL_ASSERT1(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + } \ + } + + #define SSL_ASSERT2(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + } \ + } + + #define SSL_ASSERT3(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + } \ + } +#elif defined(CONFIG_OPENSSL_ASSERT_EXIT) + #define SSL_ASSERT1(s) \ + { \ + if (!(s)) { \ + return -1; \ + } \ + } + + #define SSL_ASSERT2(s) \ + { \ + if (!(s)) { \ + return NULL; \ + } \ + } + + #define SSL_ASSERT3(s) \ + { \ + if (!(s)) { \ + return ; \ + } \ + } +#elif defined(CONFIG_OPENSSL_ASSERT_DEBUG_EXIT) + #define SSL_ASSERT1(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + return -1; \ + } \ + } + + #define SSL_ASSERT2(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + return NULL; \ + } \ + } + + #define SSL_ASSERT3(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + return ; \ + } \ + } +#elif defined(CONFIG_OPENSSL_ASSERT_DEBUG_BLOCK) + #define SSL_ASSERT1(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + while (1); \ + } \ + } + + #define SSL_ASSERT2(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + while (1); \ + } \ + } + + #define SSL_ASSERT3(s) \ + { \ + if (!(s)) { \ + SSL_SHOW_LOCATION(); \ + while (1); \ + } \ + } #else - #define SSL_DEBUG_LOCATION() + #define SSL_ASSERT1(s) + #define SSL_ASSERT2(s) + #define SSL_ASSERT3(s) #endif -#if SSL_ASSERT_ENABLE - #define SSL_ASSERT(s) { if (!(s)) { SSL_DEBUG_LOCATION(); } } -#else - #define SSL_ASSERT(s) -#endif +#define SSL_PLATFORM_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_PLATFORM_ERROR_LEVEL SSL_DEBUG_ON -#define SSL_ERR(err, go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_ERROR_LOG(fmt, ##__VA_ARGS__); ret = err; goto go; } +#define SSL_CERT_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_CERT_ERROR_LEVEL SSL_DEBUG_ON -#define SSL_RET(go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_ERROR_LOG(fmt, ##__VA_ARGS__); goto go; } +#define SSL_PKEY_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_PKEY_ERROR_LEVEL SSL_DEBUG_ON -#define SSL_DEBUG(level, fmt, ...) { if (level > SSL_DEBUG_LEVEL) {SSL_PRINT_LOG(fmt, ##__VA_ARGS__);} } +#define SSL_X509_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_X509_ERROR_LEVEL SSL_DEBUG_ON + +#define SSL_LIB_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_LIB_ERROR_LEVEL SSL_DEBUG_ON + +#define SSL_STACK_DEBUG_LEVEL SSL_DEBUG_OFF +#define SSL_STACK_ERROR_LEVEL SSL_DEBUG_ON #ifdef __cplusplus -} + } #endif #endif diff --git a/components/openssl/include/platform/ssl_opt.h b/components/openssl/include/platform/ssl_opt.h index 01d438eb8a..a9c55e8c46 100644 --- a/components/openssl/include/platform/ssl_opt.h +++ b/components/openssl/include/platform/ssl_opt.h @@ -15,34 +15,6 @@ #ifndef _SSL_OPT_H_ #define _SSL_OPT_H_ -#ifdef __cplusplus - extern "C" { -#endif - -/** - * if not define "ESP32_IDF_PLATFORM", system will use esp8266 platform interface - */ -#define ESP32_IDF_PLATFORM - -/** - * openssl debug print function enable - */ -#define SSL_DEBUG_ENBALE 0 - -/** - * openssl debug print function level. function whose level is lower that "SSL_DEBUG_LEVEL" - * will not print message - */ -#define SSL_DEBUG_LEVEL 0 - -/** - * openssl assert function enable, it will check the input paramter and print the message - */ -#define SSL_ASSERT_ENABLE 0 - -/** - * openssl location function enable, it will print location of the positioning error - */ -#define SSL_DEBUG_LOCATION_ENABLE 0 +#include "sdkconfig.h" #endif diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index a516d57422..cbbe3aa3a2 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -19,6 +19,7 @@ extern "C" { #endif +#include #include "ssl_types.h" #include "ssl_port.h" @@ -53,4 +54,8 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len); long ssl_pm_get_verify_result(const SSL *ssl); +#ifdef __cplusplus + } +#endif + #endif diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h index 35c8dc18f9..492ea405b2 100644 --- a/components/openssl/include/platform/ssl_port.h +++ b/components/openssl/include/platform/ssl_port.h @@ -19,31 +19,27 @@ extern "C" { #endif -#include "platform/ssl_opt.h" - -#ifdef ESP32_IDF_PLATFORM - #include "esp_types.h" #include "esp_log.h" +#include "string.h" +#include "malloc.h" void *ssl_mem_zalloc(size_t size); -void *ssl_mem_malloc(size_t size); -void ssl_mem_free(void *p); -void* ssl_memcpy(void *to, const void *from, size_t size); -size_t ssl_strlen(const char *src); +#define ssl_mem_malloc malloc +#define ssl_mem_free free -void ssl_speed_up_enter(void); -void ssl_speed_up_exit(void); +#define ssl_memcpy memcpy +#define ssl_strlen strlen -#define SSL_PRINT_LOG(fmt, ...) ESP_LOGD("openssl", fmt, ##__VA_ARGS__) -#define SSL_ERROR_LOG(fmt, ...) ESP_LOGE("openssl", fmt, ##__VA_ARGS__) -#define SSL_LOCAL_LOG(fmt, ...) ESP_LOGD("openssl", fmt, ##__VA_ARGS__) +#define ssl_speed_up_enter() +#define ssl_speed_up_exit() -#elif defined(SSL_PLATFORM_USER_INCLUDE) - -SSL_PLATFORM_USER_INCLUDE +#define SSL_DEBUG_FL +#define SSL_DEBUG_LOG(fmt, ...) ESP_LOGI("openssl", fmt, ##__VA_ARGS__) +#ifdef __cplusplus + } #endif #endif diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c index 0193a441e0..5c608125ac 100644 --- a/components/openssl/library/ssl_cert.c +++ b/components/openssl/library/ssl_cert.c @@ -29,8 +29,10 @@ CERT *__ssl_cert_new(CERT *ic) EVP_PKEY *ipk; cert = ssl_mem_zalloc(sizeof(CERT)); - if (!cert) - SSL_RET(failed1, "ssl_mem_zalloc\n"); + if (!cert) { + SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "no enough memory > (cert)"); + goto no_mem; + } if (ic) { ipk = ic->pkey; @@ -41,20 +43,24 @@ CERT *__ssl_cert_new(CERT *ic) } cert->pkey = __EVP_PKEY_new(ipk); - if (!cert->pkey) - SSL_RET(failed2, "__EVP_PKEY_new\n"); + if (!cert->pkey) { + SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "__EVP_PKEY_new() return NULL"); + goto pkey_err; + } cert->x509 = __X509_new(ix); - if (!cert->x509) - SSL_RET(failed3, "__X509_new\n"); + if (!cert->x509) { + SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "__X509_new() return NULL"); + goto x509_err; + } return cert; -failed3: +x509_err: EVP_PKEY_free(cert->pkey); -failed2: +pkey_err: ssl_mem_free(cert); -failed1: +no_mem: return NULL; } @@ -71,6 +77,8 @@ CERT *ssl_cert_new(void) */ void ssl_cert_free(CERT *cert) { + SSL_ASSERT3(cert); + X509_free(cert->x509); EVP_PKEY_free(cert->pkey); diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 23b8bf4cea..8b539826dc 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -21,11 +21,49 @@ #define SSL_SEND_DATA_MAX_LENGTH 1460 +/** + * @brief create a new SSL session object + */ +static SSL_SESSION* SSL_SESSION_new(void) +{ + SSL_SESSION *session; + + session = ssl_mem_zalloc(sizeof(SSL_SESSION)); + if (!session) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no enough memory > (session)"); + goto failed1; + } + + session->peer = X509_new(); + if (!session->peer) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "X509_new() return NULL"); + goto failed2; + } + + return session; + +failed2: + ssl_mem_free(session); +failed1: + return NULL; +} + +/** + * @brief free a new SSL session object + */ +static void SSL_SESSION_free(SSL_SESSION *session) +{ + X509_free(session->peer); + ssl_mem_free(session); +} + /** * @brief Discover whether the current connection is in the error state */ int ossl_statem_in_error(const SSL *ssl) { + SSL_ASSERT1(ssl); + if (ssl->statem.state == MSG_FLOW_ERROR) return 1; @@ -37,6 +75,8 @@ int ossl_statem_in_error(const SSL *ssl) */ int SSL_want(const SSL *ssl) { + SSL_ASSERT1(ssl); + return ssl->rwstate; } @@ -45,6 +85,8 @@ int SSL_want(const SSL *ssl) */ int SSL_want_nothing(const SSL *ssl) { + SSL_ASSERT1(ssl); + return (SSL_want(ssl) == SSL_NOTHING); } @@ -53,6 +95,8 @@ int SSL_want_nothing(const SSL *ssl) */ int SSL_want_read(const SSL *ssl) { + SSL_ASSERT1(ssl); + return (SSL_want(ssl) == SSL_READING); } @@ -61,6 +105,8 @@ int SSL_want_read(const SSL *ssl) */ int SSL_want_write(const SSL *ssl) { + SSL_ASSERT1(ssl); + return (SSL_want(ssl) == SSL_WRITING); } @@ -69,6 +115,8 @@ int SSL_want_write(const SSL *ssl) */ int SSL_want_x509_lookup(const SSL *ssl) { + SSL_ASSERT1(ssl); + return (SSL_want(ssl) == SSL_WRITING); } @@ -79,7 +127,7 @@ int SSL_get_error(const SSL *ssl, int ret_code) { int ret = SSL_ERROR_SYSCALL; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); if (ret_code > 0) ret = SSL_ERROR_NONE; @@ -110,45 +158,13 @@ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) { OSSL_HANDSHAKE_STATE state; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); state = SSL_METHOD_CALL(get_state, ssl); return state; } -/** - * @brief create a new SSL session object - */ -SSL_SESSION* SSL_SESSION_new(void) -{ - SSL_SESSION *session; - - session = ssl_mem_zalloc(sizeof(SSL_SESSION)); - if (!session) - SSL_RET(failed1, "ssl_mem_zalloc\n"); - - session->peer = X509_new(); - if (!session->peer) - SSL_RET(failed2, "X509_new\n"); - - return session; - -failed2: - ssl_mem_free(session); -failed1: - return NULL; -} - -/** - * @brief free a new SSL session object - */ -void SSL_SESSION_free(SSL_SESSION *session) -{ - X509_free(session->peer); - ssl_mem_free(session); -} - /** * @brief create a SSL context */ @@ -158,19 +174,28 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) CERT *cert; X509 *client_ca; - if (!method) SSL_RET(go_failed1, "method:NULL\n"); + if (!method) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no no_method"); + return NULL; + } client_ca = X509_new(); - if (!client_ca) - SSL_RET(go_failed1, "X509_new\n"); + if (!client_ca) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "X509_new() return NULL"); + goto failed1; + } cert = ssl_cert_new(); - if (!cert) - SSL_RET(go_failed2, "ssl_cert_new\n"); + if (!cert) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "ssl_cert_new() return NULL"); + goto failed2; + } ctx = (SSL_CTX *)ssl_mem_zalloc(sizeof(SSL_CTX)); - if (!ctx) - SSL_RET(go_failed3, "ssl_mem_zalloc:ctx\n"); + if (!ctx) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no enough memory > (ctx)"); + goto failed3; + } ctx->method = method; ctx->client_CA = client_ca; @@ -180,11 +205,11 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) return ctx; -go_failed3: +failed3: ssl_cert_free(cert); -go_failed2: +failed2: X509_free(client_ca); -go_failed1: +failed1: return NULL; } @@ -193,7 +218,7 @@ go_failed1: */ void SSL_CTX_free(SSL_CTX* ctx) { - SSL_ASSERT(ctx); + SSL_ASSERT3(ctx); ssl_cert_free(ctx->cert); @@ -207,8 +232,8 @@ void SSL_CTX_free(SSL_CTX* ctx) */ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) { - SSL_ASSERT(ctx); - SSL_ASSERT(meth); + SSL_ASSERT1(ctx); + SSL_ASSERT1(meth); ctx->method = meth; @@ -222,7 +247,7 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) */ const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) { - SSL_ASSERT(ctx); + SSL_ASSERT2(ctx); return ctx->method; } @@ -235,24 +260,34 @@ SSL *SSL_new(SSL_CTX *ctx) int ret = 0; SSL *ssl; - if (!ctx) - SSL_RET(failed1, "ctx:NULL\n"); + if (!ctx) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no ctx"); + return NULL; + } ssl = (SSL *)ssl_mem_zalloc(sizeof(SSL)); - if (!ssl) - SSL_RET(failed1, "ssl_mem_zalloc\n"); + if (!ssl) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no enough memory > (ssl)"); + goto failed1; + } ssl->session = SSL_SESSION_new(); - if (!ssl->session) - SSL_RET(failed2, "SSL_SESSION_new\n"); + if (!ssl->session) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_SESSION_new() return NULL"); + goto failed2; + } ssl->cert = __ssl_cert_new(ctx->cert); - if (!ssl->cert) - SSL_RET(failed3, "__ssl_cert_new\n"); + if (!ssl->cert) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "__ssl_cert_new() return NULL"); + goto failed3; + } ssl->client_CA = __X509_new(ctx->client_CA); - if (!ssl->client_CA) - SSL_RET(failed4, "__X509_new\n"); + if (!ssl->client_CA) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "__X509_new() return NULL"); + goto failed4; + } ssl->ctx = ctx; ssl->method = ctx->method; @@ -263,8 +298,10 @@ SSL *SSL_new(SSL_CTX *ctx) ssl->verify_mode = ctx->verify_mode; ret = SSL_METHOD_CALL(new, ssl); - if (ret) - SSL_RET(failed5, "ssl_new\n"); + if (ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_METHOD_CALL(new) return %d", ret); + goto failed5; + } ssl->rwstate = SSL_NOTHING; @@ -287,7 +324,7 @@ failed1: */ void SSL_free(SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT3(ssl); SSL_METHOD_CALL(free, ssl); @@ -307,7 +344,7 @@ int SSL_do_handshake(SSL *ssl) { int ret; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); ret = SSL_METHOD_CALL(handshake, ssl); @@ -319,7 +356,7 @@ int SSL_do_handshake(SSL *ssl) */ int SSL_connect(SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return SSL_do_handshake(ssl); } @@ -329,7 +366,7 @@ int SSL_connect(SSL *ssl) */ int SSL_accept(SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return SSL_do_handshake(ssl); } @@ -341,7 +378,7 @@ int SSL_shutdown(SSL *ssl) { int ret; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); if (SSL_get_state(ssl) != TLS_ST_OK) return 1; @@ -357,21 +394,25 @@ int SSL_clear(SSL *ssl) { int ret; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); ret = SSL_shutdown(ssl); - if (1 != ret) - SSL_ERR(0, go_failed1, "SSL_shutdown\n"); + if (1 != ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_shutdown return %d", ret); + goto failed1; + } SSL_METHOD_CALL(free, ssl); ret = SSL_METHOD_CALL(new, ssl); - if (!ret) - SSL_ERR(0, go_failed1, "ssl_new\n"); + if (!ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_METHOD_CALL(new) return %d", ret); + goto failed1; + } return 1; -go_failed1: +failed1: return ret; } @@ -382,9 +423,9 @@ int SSL_read(SSL *ssl, void *buffer, int len) { int ret; - SSL_ASSERT(ssl); - SSL_ASSERT(buffer); - SSL_ASSERT(len); + SSL_ASSERT1(ssl); + SSL_ASSERT1(buffer); + SSL_ASSERT1(len); ssl->rwstate = SSL_READING; @@ -405,9 +446,9 @@ int SSL_write(SSL *ssl, const void *buffer, int len) int send_bytes; const unsigned char *pbuf; - SSL_ASSERT(ssl); - SSL_ASSERT(buffer); - SSL_ASSERT(len); + SSL_ASSERT1(ssl); + SSL_ASSERT1(buffer); + SSL_ASSERT1(len); ssl->rwstate = SSL_WRITING; @@ -422,7 +463,7 @@ int SSL_write(SSL *ssl, const void *buffer, int len) else bytes = send_bytes; - ret = SSL_METHOD_CALL(send, ssl, buffer, bytes); + ret = SSL_METHOD_CALL(send, ssl, pbuf, bytes); if (ret > 0) { pbuf += ret; send_bytes -= ret; @@ -443,7 +484,7 @@ int SSL_write(SSL *ssl, const void *buffer, int len) */ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); return ssl->ctx; } @@ -453,7 +494,7 @@ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) */ const SSL_METHOD *SSL_get_ssl_method(SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); return ssl->method; } @@ -465,22 +506,26 @@ int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method) { int ret; - SSL_ASSERT(ssl); - SSL_ASSERT(method); + SSL_ASSERT1(ssl); + SSL_ASSERT1(method); if (ssl->version != method->version) { ret = SSL_shutdown(ssl); - if (1 != ret) - SSL_ERR(0, go_failed1, "SSL_shutdown\n"); + if (1 != ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_shutdown return %d", ret); + goto failed1; + } SSL_METHOD_CALL(free, ssl); ssl->method = method; ret = SSL_METHOD_CALL(new, ssl); - if (!ret) - SSL_ERR(0, go_failed1, "ssl_new\n"); + if (!ret) { + SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "SSL_METHOD_CALL(new) return %d", ret); + goto failed1; + } } else { ssl->method = method; } @@ -488,7 +533,7 @@ int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method) return 1; -go_failed1: +failed1: return ret; } @@ -497,7 +542,7 @@ go_failed1: */ int SSL_get_shutdown(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return ssl->shutdown; } @@ -507,7 +552,7 @@ int SSL_get_shutdown(const SSL *ssl) */ void SSL_set_shutdown(SSL *ssl, int mode) { - SSL_ASSERT(ssl); + SSL_ASSERT3(ssl); ssl->shutdown = mode; } @@ -520,7 +565,7 @@ int SSL_pending(const SSL *ssl) { int ret; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); ret = SSL_METHOD_CALL(pending, ssl); @@ -534,7 +579,7 @@ int SSL_has_pending(const SSL *ssl) { int ret; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); if (SSL_pending(ssl)) ret = 1; @@ -549,6 +594,8 @@ int SSL_has_pending(const SSL *ssl) */ unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op) { + SSL_ASSERT1(ctx); + return ctx->options &= ~op; } @@ -557,6 +604,8 @@ unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op) */ unsigned long SSL_CTX_get_options(SSL_CTX *ctx) { + SSL_ASSERT1(ctx); + return ctx->options; } @@ -565,6 +614,8 @@ unsigned long SSL_CTX_get_options(SSL_CTX *ctx) */ unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt) { + SSL_ASSERT1(ctx); + return ctx->options |= opt; } @@ -573,7 +624,7 @@ unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt) */ unsigned long SSL_clear_options(SSL *ssl, unsigned long op) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return ssl->options & ~op; } @@ -583,7 +634,7 @@ unsigned long SSL_clear_options(SSL *ssl, unsigned long op) */ unsigned long SSL_get_options(SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return ssl->options; } @@ -593,7 +644,7 @@ unsigned long SSL_get_options(SSL *ssl) */ unsigned long SSL_set_options(SSL *ssl, unsigned long op) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return ssl->options |= op; } @@ -605,7 +656,7 @@ int SSL_get_fd(const SSL *ssl) { int ret; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); ret = SSL_METHOD_CALL(get_fd, ssl, 0); @@ -619,7 +670,7 @@ int SSL_get_rfd(const SSL *ssl) { int ret; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); ret = SSL_METHOD_CALL(get_fd, ssl, 0); @@ -633,7 +684,7 @@ int SSL_get_wfd(const SSL *ssl) { int ret; - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); ret = SSL_METHOD_CALL(get_fd, ssl, 0); @@ -645,8 +696,8 @@ int SSL_get_wfd(const SSL *ssl) */ int SSL_set_fd(SSL *ssl, int fd) { - SSL_ASSERT(ssl); - SSL_ASSERT(fd >= 0); + SSL_ASSERT1(ssl); + SSL_ASSERT1(fd >= 0); SSL_METHOD_CALL(set_fd, ssl, fd, 0); @@ -658,8 +709,8 @@ int SSL_set_fd(SSL *ssl, int fd) */ int SSL_set_rfd(SSL *ssl, int fd) { - SSL_ASSERT(ssl); - SSL_ASSERT(fd >= 0); + SSL_ASSERT1(ssl); + SSL_ASSERT1(fd >= 0); SSL_METHOD_CALL(set_fd, ssl, fd, 0); @@ -671,8 +722,8 @@ int SSL_set_rfd(SSL *ssl, int fd) */ int SSL_set_wfd(SSL *ssl, int fd) { - SSL_ASSERT(ssl); - SSL_ASSERT(fd >= 0); + SSL_ASSERT1(ssl); + SSL_ASSERT1(fd >= 0); SSL_METHOD_CALL(set_fd, ssl, fd, 0); @@ -684,7 +735,7 @@ int SSL_set_wfd(SSL *ssl, int fd) */ int SSL_version(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return ssl->version; } @@ -715,7 +766,7 @@ static const char* ssl_protocol_to_string(int version) */ const char *SSL_get_version(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); return ssl_protocol_to_string(SSL_version(ssl)); } @@ -987,7 +1038,7 @@ const char *SSL_rstate_string(SSL *ssl) { const char *str; - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); switch (ssl->rlayer.rstate) { @@ -1015,7 +1066,7 @@ const char *SSL_rstate_string_long(SSL *ssl) { const char *str = "unknown"; - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); switch (ssl->rlayer.rstate) { @@ -1042,7 +1093,7 @@ char *SSL_state_string(const SSL *ssl) { char *str = "UNKWN "; - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); if (ossl_statem_in_error(ssl)) str = "SSLERR"; @@ -1150,7 +1201,7 @@ char *SSL_state_string_long(const SSL *ssl) { char *str = "UNKWN "; - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); if (ossl_statem_in_error(ssl)) str = "SSLERR"; @@ -1262,8 +1313,7 @@ char *SSL_state_string_long(const SSL *ssl) */ void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len) { - SSL_ASSERT(ctx); - SSL_ASSERT(len); + SSL_ASSERT3(ctx); ctx->read_buffer_len = len; } @@ -1273,8 +1323,8 @@ void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len) */ void SSL_set_default_read_buffer_len(SSL *ssl, size_t len) { - SSL_ASSERT(ssl); - SSL_ASSERT(len); + SSL_ASSERT3(ssl); + SSL_ASSERT3(len); SSL_METHOD_CALL(set_bufflen, ssl, len); } @@ -1284,7 +1334,7 @@ void SSL_set_default_read_buffer_len(SSL *ssl, size_t len) */ void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)) { - SSL_ASSERT(ssl); + SSL_ASSERT3(ssl); ssl->info_callback = cb; } @@ -1294,7 +1344,7 @@ void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int v */ int SSL_CTX_up_ref(SSL_CTX *ctx) { - SSL_ASSERT(ctx); + SSL_ASSERT1(ctx); /** * no support multi-thread SSL here @@ -1309,7 +1359,7 @@ int SSL_CTX_up_ref(SSL_CTX *ctx) */ void SSL_set_security_level(SSL *ssl, int level) { - SSL_ASSERT(ssl); + SSL_ASSERT3(ssl); ssl->cert->sec_level = level; } @@ -1319,7 +1369,7 @@ void SSL_set_security_level(SSL *ssl, int level) */ int SSL_get_security_level(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return ssl->cert->sec_level; } @@ -1329,7 +1379,7 @@ int SSL_get_security_level(const SSL *ssl) */ int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { - SSL_ASSERT(ctx); + SSL_ASSERT1(ctx); return ctx->verify_mode; } @@ -1341,7 +1391,7 @@ long SSL_CTX_set_timeout(SSL_CTX *ctx, long t) { long l; - SSL_ASSERT(ctx); + SSL_ASSERT1(ctx); l = ctx->session_timeout; ctx->session_timeout = t; @@ -1354,7 +1404,7 @@ long SSL_CTX_set_timeout(SSL_CTX *ctx, long t) */ long SSL_CTX_get_timeout(const SSL_CTX *ctx) { - SSL_ASSERT(ctx); + SSL_ASSERT1(ctx); return ctx->session_timeout; } @@ -1364,7 +1414,7 @@ long SSL_CTX_get_timeout(const SSL_CTX *ctx) */ void SSL_set_read_ahead(SSL *ssl, int yes) { - SSL_ASSERT(ssl); + SSL_ASSERT3(ssl); ssl->rlayer.read_ahead = yes; } @@ -1374,7 +1424,7 @@ void SSL_set_read_ahead(SSL *ssl, int yes) */ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { - SSL_ASSERT(ctx); + SSL_ASSERT3(ctx); ctx->read_ahead = yes; } @@ -1384,7 +1434,7 @@ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) */ int SSL_get_read_ahead(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return ssl->rlayer.read_ahead; } @@ -1394,7 +1444,7 @@ int SSL_get_read_ahead(const SSL *ssl) */ long SSL_CTX_get_read_ahead(SSL_CTX *ctx) { - SSL_ASSERT(ctx); + SSL_ASSERT1(ctx); return ctx->read_ahead; } @@ -1404,7 +1454,7 @@ long SSL_CTX_get_read_ahead(SSL_CTX *ctx) */ long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx) { - SSL_ASSERT(ctx); + SSL_ASSERT1(ctx); return ctx->read_ahead; } @@ -1414,7 +1464,7 @@ long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx) */ long SSL_set_time(SSL *ssl, long t) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); ssl->session->time = t; @@ -1426,7 +1476,7 @@ long SSL_set_time(SSL *ssl, long t) */ long SSL_set_timeout(SSL *ssl, long t) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); ssl->session->timeout = t; @@ -1438,7 +1488,7 @@ long SSL_set_timeout(SSL *ssl, long t) */ long SSL_get_verify_result(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return SSL_METHOD_CALL(get_verify_result, ssl); } @@ -1448,7 +1498,7 @@ long SSL_get_verify_result(const SSL *ssl) */ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) { - SSL_ASSERT(ctx); + SSL_ASSERT1(ctx); return ctx->param.depth; } @@ -1458,7 +1508,7 @@ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) */ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { - SSL_ASSERT(ctx); + SSL_ASSERT3(ctx); ctx->param.depth = depth; } @@ -1468,7 +1518,7 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) */ int SSL_get_verify_depth(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT1(ssl); return ssl->param.depth; } @@ -1478,7 +1528,7 @@ int SSL_get_verify_depth(const SSL *ssl) */ void SSL_set_verify_depth(SSL *ssl, int depth) { - SSL_ASSERT(ssl); + SSL_ASSERT3(ssl); ssl->param.depth = depth; } @@ -1488,7 +1538,7 @@ void SSL_set_verify_depth(SSL *ssl, int depth) */ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) { - SSL_ASSERT(ctx); + SSL_ASSERT3(ctx); ctx->verify_mode = mode; ctx->default_verify_callback = verify_callback; @@ -1499,7 +1549,7 @@ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509 */ void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) { - SSL_ASSERT(ssl); + SSL_ASSERT3(ssl); ssl->verify_mode = mode; ssl->verify_callback = verify_callback; diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index dbd82dc9c2..567a33e2c2 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -26,8 +26,10 @@ EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk) EVP_PKEY *pkey; pkey = ssl_mem_zalloc(sizeof(EVP_PKEY)); - if (!pkey) - SSL_RET(failed1, "ssl_mem_zalloc\n"); + if (!pkey) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "no enough memory > (pkey)"); + goto no_mem; + } if (ipk) { pkey->method = ipk->method; @@ -36,14 +38,16 @@ EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk) } ret = EVP_PKEY_METHOD_CALL(new, pkey, ipk); - if (ret) - SSL_RET(failed2, "EVP_PKEY_METHOD_CALL\n"); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(new) return %d", ret); + goto failed; + } return pkey; -failed2: +failed: ssl_mem_free(pkey); -failed1: +no_mem: return NULL; } @@ -60,6 +64,8 @@ EVP_PKEY* EVP_PKEY_new(void) */ void EVP_PKEY_free(EVP_PKEY *pkey) { + SSL_ASSERT3(pkey); + EVP_PKEY_METHOD_CALL(free, pkey); ssl_mem_free(pkey); @@ -78,22 +84,27 @@ EVP_PKEY *d2i_PrivateKey(int type, int ret; EVP_PKEY *pkey; - SSL_ASSERT(pp); - SSL_ASSERT(*pp); - SSL_ASSERT(length); + SSL_ASSERT2(pp); + SSL_ASSERT2(*pp); + SSL_ASSERT2(length); if (a && *a) { pkey = *a; } else { pkey = EVP_PKEY_new();; - if (!pkey) - SSL_RET(failed1, "EVP_PKEY_new\n"); + if (!pkey) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_new() return NULL"); + goto failed1; + } + m = 1; } ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, length); - if (ret) - SSL_RET(failed2, "EVP_PKEY_METHOD_CALL\n"); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(load) return %d", ret); + goto failed2; + } if (a) *a = pkey; @@ -112,8 +123,8 @@ failed1: */ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) { - SSL_ASSERT(ctx); - SSL_ASSERT(pkey); + SSL_ASSERT1(ctx); + SSL_ASSERT1(pkey); if (ctx->cert->pkey == pkey) return 1; @@ -131,8 +142,8 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) */ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { - SSL_ASSERT(ssl); - SSL_ASSERT(pkey); + SSL_ASSERT1(ssl); + SSL_ASSERT1(pkey); if (ssl->cert->pkey == pkey) return 1; @@ -155,12 +166,16 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, EVP_PKEY *pk; pk = d2i_PrivateKey(0, NULL, &d, len); - if (!pk) - SSL_RET(failed1, "d2i_PrivateKey\n"); + if (!pk) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL"); + goto failed1; + } ret = SSL_CTX_use_PrivateKey(ctx, pk); - if (!ret) - SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); + if (!ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_PrivateKey() return %d", ret); + goto failed2; + } return 1; @@ -180,12 +195,16 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, EVP_PKEY *pk; pk = d2i_PrivateKey(0, NULL, &d, len); - if (!pk) - SSL_RET(failed1, "d2i_PrivateKey\n"); + if (!pk) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL"); + goto failed1; + } ret = SSL_use_PrivateKey(ssl, pk); - if (!ret) - SSL_RET(failed2, "SSL_use_PrivateKey\n"); + if (!ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_PrivateKey() return %d", ret); + goto failed2; + } return 1; diff --git a/components/openssl/library/ssl_stack.c b/components/openssl/library/ssl_stack.c index 5dbb69af9d..da836daf9c 100644 --- a/components/openssl/library/ssl_stack.c +++ b/components/openssl/library/ssl_stack.c @@ -31,12 +31,16 @@ OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) char **data; stack = ssl_mem_zalloc(sizeof(OPENSSL_STACK)); - if (!stack) - SSL_RET(failed1, "ssl_mem_zalloc\n"); + if (!stack) { + SSL_DEBUG(SSL_STACK_ERROR_LEVEL, "no enough memory > (stack)"); + goto no_mem1; + } data = ssl_mem_zalloc(sizeof(*data) * MIN_NODES); - if (!data) - SSL_RET(failed2, "ssl_mem_zalloc\n"); + if (!data) { + SSL_DEBUG(SSL_STACK_ERROR_LEVEL, "no enough memory > (data)"); + goto no_mem2; + } stack->data = data; stack->num_alloc = MIN_NODES; @@ -44,9 +48,9 @@ OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) return stack; -failed2: +no_mem2: ssl_mem_free(stack); -failed1: +no_mem1: return NULL; } @@ -63,7 +67,7 @@ OPENSSL_STACK *OPENSSL_sk_new_null(void) */ void OPENSSL_sk_free(OPENSSL_STACK *stack) { - SSL_ASSERT(stack); + SSL_ASSERT3(stack); ssl_mem_free(stack->data); ssl_mem_free(stack); diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index d0426db18c..ef0503c053 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -34,8 +34,10 @@ X509* __X509_new(X509 *ix) X509 *x; x = ssl_mem_zalloc(sizeof(X509)); - if (!x) - SSL_RET(failed1, "ssl_mem_zalloc\n"); + if (!x) { + SSL_DEBUG(SSL_X509_ERROR_LEVEL, "no enough memory > (x)"); + goto no_mem; + } if (ix) x->method = ix->method; @@ -43,14 +45,16 @@ X509* __X509_new(X509 *ix) x->method = X509_method(); ret = X509_METHOD_CALL(new, x, ix); - if (ret) - SSL_RET(failed2, "x509_new\n"); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(new) return %d", ret); + goto failed; + } return x; -failed2: +failed: ssl_mem_free(x); -failed1: +no_mem: return NULL; } @@ -67,6 +71,8 @@ X509* X509_new(void) */ void X509_free(X509 *x) { + SSL_ASSERT3(x); + X509_METHOD_CALL(free, x); ssl_mem_free(x); @@ -82,21 +88,25 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) int ret; X509 *x; - SSL_ASSERT(buffer); - SSL_ASSERT(len); + SSL_ASSERT2(buffer); + SSL_ASSERT2(len); if (cert && *cert) { x = *cert; } else { x = X509_new(); - if (!x) - SSL_RET(failed1, "X509_new\n"); + if (!x) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_new() return NULL"); + goto failed1; + } m = 1; } ret = X509_METHOD_CALL(load, x, buffer, len); - if (ret) - SSL_RET(failed2, "x509_load\n"); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret); + goto failed2; + } return x; @@ -112,8 +122,8 @@ failed1: */ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) { - SSL_ASSERT(ctx); - SSL_ASSERT(x); + SSL_ASSERT1(ctx); + SSL_ASSERT1(x); if (ctx->client_CA == x) return 1; @@ -130,8 +140,8 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) */ int SSL_add_client_CA(SSL *ssl, X509 *x) { - SSL_ASSERT(ssl); - SSL_ASSERT(x); + SSL_ASSERT1(ssl); + SSL_ASSERT1(x); if (ssl->client_CA == x) return 1; @@ -148,8 +158,8 @@ int SSL_add_client_CA(SSL *ssl, X509 *x) */ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { - SSL_ASSERT(ctx); - SSL_ASSERT(x); + SSL_ASSERT1(ctx); + SSL_ASSERT1(x); if (ctx->cert->x509 == x) return 1; @@ -166,8 +176,8 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) */ int SSL_use_certificate(SSL *ssl, X509 *x) { - SSL_ASSERT(ssl); - SSL_ASSERT(x); + SSL_ASSERT1(ssl); + SSL_ASSERT1(x); if (ssl->cert->x509 == x) return 1; @@ -184,7 +194,7 @@ int SSL_use_certificate(SSL *ssl, X509 *x) */ X509 *SSL_get_certificate(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); return ssl->cert->x509; } @@ -199,12 +209,16 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, X509 *x; x = d2i_X509(NULL, d, len); - if (!x) - SSL_RET(failed1, "d2i_X509\n"); + if (!x) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL"); + goto failed1; + } ret = SSL_CTX_use_certificate(ctx, x); - if (!ret) - SSL_RET(failed2, "SSL_CTX_use_certificate\n"); + if (!ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_certificate() return %d", ret); + goto failed2; + } return 1; @@ -224,12 +238,16 @@ int SSL_use_certificate_ASN1(SSL *ssl, int len, X509 *x; x = d2i_X509(NULL, d, len); - if (!x) - SSL_RET(failed1, "d2i_X509\n"); + if (!x) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL"); + goto failed1; + } ret = SSL_use_certificate(ssl, x); - if (!ret) - SSL_RET(failed2, "SSL_use_certificate\n"); + if (!ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_certificate() return %d", ret); + goto failed2; + } return 1; @@ -260,7 +278,7 @@ int SSL_use_certificate_file(SSL *ssl, const char *file, int type) */ X509 *SSL_get_peer_certificate(const SSL *ssl) { - SSL_ASSERT(ssl); + SSL_ASSERT2(ssl); return ssl->session->peer; } diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 15015107f0..1281965e2c 100755 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -25,13 +25,7 @@ #include "mbedtls/error.h" #include "mbedtls/certs.h" -#if 0 - #define DEBUG_LOAD_BUF_STRING(str) SSL_DEBUG(1, "%s\n", str) -#else - #define DEBUG_LOAD_BUF_STRING(str) -#endif - -#define X509_INFO_STRING_LENGTH 1024 +#define X509_INFO_STRING_LENGTH 8192 struct ssl_pm { @@ -63,13 +57,36 @@ struct pkey_pm mbedtls_pk_context *ex_pkey; }; - unsigned int max_content_len; - /*********************************************************************************************/ /************************************ SSL arch interface *************************************/ +#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG + +/* mbedtls debug level */ +#define MBEDTLS_DEBUG_LEVEL 4 + +/** + * @brief mbedtls debug function + */ +static void ssl_platform_debug(void *ctx, int level, + const char *file, int line, + const char *str) +{ + /* Shorten 'file' from the whole file path to just the filename + + This is a bit wasteful because the macros are compiled in with + the full _FILE_ path in each case. + */ + char *file_sep = rindex(file, '/'); + if(file_sep) + file = file_sep + 1; + + SSL_DEBUG(SSL_DEBUG_ON, "%s:%d %s", file, line, str); +} +#endif + /** * @brief create SSL low-level object */ @@ -87,11 +104,13 @@ int ssl_pm_new(SSL *ssl) const SSL_METHOD *method = ssl->method; ssl_pm = ssl_mem_zalloc(sizeof(struct ssl_pm)); - if (!ssl_pm) - SSL_ERR(ret, failed1, "ssl_mem_zalloc\n"); + if (!ssl_pm) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (ssl_pm)"); + goto no_mem; + } max_content_len = ssl->ctx->read_buffer_len; - + mbedtls_net_init(&ssl_pm->fd); mbedtls_net_init(&ssl_pm->cl_fd); @@ -101,8 +120,10 @@ int ssl_pm_new(SSL *ssl) mbedtls_ssl_init(&ssl_pm->ssl); ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len); - if (ret) - SSL_ERR(ret, failed2, "mbedtls_ctr_drbg_seed:[-0x%x]\n", -ret); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ctr_drbg_seed() return -0x%x", -ret); + goto mbedtls_err1; + } if (method->endpoint) { endpoint = MBEDTLS_SSL_IS_SERVER; @@ -110,8 +131,10 @@ int ssl_pm_new(SSL *ssl) endpoint = MBEDTLS_SSL_IS_CLIENT; } ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); - if (ret) - SSL_ERR(ret, failed2, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_config_defaults() return -0x%x", -ret); + goto mbedtls_err2; + } if (TLS_ANY_VERSION != ssl->version) { if (TLS1_2_VERSION == ssl->version) @@ -132,11 +155,18 @@ int ssl_pm_new(SSL *ssl) mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg); +#ifdef CONFIG_OPENSSL_LOWLEVEL_DEBUG + mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL); + mbedtls_ssl_conf_dbg(&ssl_pm->conf, ssl_platform_debug, NULL); +#else mbedtls_ssl_conf_dbg(&ssl_pm->conf, NULL, NULL); +#endif ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); - if (ret) - SSL_ERR(ret, failed3, "mbedtls_ssl_setup:[-0x%x]\n", -ret); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_setup() return -0x%x", -ret); + goto mbedtls_err2; + } mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL); @@ -144,13 +174,13 @@ int ssl_pm_new(SSL *ssl) return 0; -failed3: +mbedtls_err2: mbedtls_ssl_config_free(&ssl_pm->conf); mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); -failed2: +mbedtls_err1: mbedtls_entropy_free(&ssl_pm->entropy); ssl_mem_free(ssl_pm); -failed1: +no_mem: return -1; } @@ -208,10 +238,12 @@ static int ssl_pm_reload_crt(SSL *ssl) ret = 0; } - if (ret) - return -1; + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_conf_own_cert() return -0x%x", -ret); + ret = -1; + } - return 0; + return ret; } /* @@ -222,16 +254,11 @@ static int mbedtls_handshake( mbedtls_ssl_context *ssl ) { int ret = 0; - if (ssl == NULL || ssl->conf == NULL) - return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; - - while (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) - { + while (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) { ret = mbedtls_ssl_handshake_step(ssl); - - SSL_DEBUG(1, "ssl ret %d state %d heap %d\n", - ret, ssl->state, system_get_free_heap_size()); - + + SSL_DEBUG(SSL_PLATFORM_DEBUG_LEVEL, "ssl ret %d state %d", ret, ssl->state); + if (ret != 0) break; } @@ -241,36 +268,31 @@ static int mbedtls_handshake( mbedtls_ssl_context *ssl ) int ssl_pm_handshake(SSL *ssl) { - int ret, mbed_ret; + int ret; struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; - mbed_ret = ssl_pm_reload_crt(ssl); - if (mbed_ret) + ret = ssl_pm_reload_crt(ssl); + if (ret) return 0; - SSL_DEBUG(1, "ssl_speed_up_enter "); ssl_speed_up_enter(); - SSL_DEBUG(1, "OK\n"); - - while((mbed_ret = mbedtls_handshake(&ssl_pm->ssl)) != 0) { - if (mbed_ret != MBEDTLS_ERR_SSL_WANT_READ && mbed_ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + + while((ret = mbedtls_handshake(&ssl_pm->ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { break; } } - - SSL_DEBUG(1, "ssl_speed_up_exit "); - ssl_speed_up_exit(); - SSL_DEBUG(1, "OK\n"); - if (!mbed_ret) { + ssl_speed_up_exit(); + + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_handshake() return -0x%x", -ret); + ret = 0; + } else { struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; - ret = 1; - x509_pm->ex_crt = (mbedtls_x509_crt *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl); - } else { - ret = 0; - SSL_DEBUG(1, "mbedtls_ssl_handshake [-0x%x]\n", -mbed_ret); + ret = 1; } return ret; @@ -278,19 +300,18 @@ int ssl_pm_handshake(SSL *ssl) int ssl_pm_shutdown(SSL *ssl) { - int ret, mbed_ret; + int ret; struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; - mbed_ret = mbedtls_ssl_close_notify(&ssl_pm->ssl); - if (!mbed_ret) { + ret = mbedtls_ssl_close_notify(&ssl_pm->ssl); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_close_notify() return -0x%x", -ret); + ret = -1; + } else { struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; - ret = 0; - x509_pm->ex_crt = NULL; } - else - ret = -1; return ret; } @@ -303,32 +324,28 @@ int ssl_pm_clear(SSL *ssl) int ssl_pm_read(SSL *ssl, void *buffer, int len) { - int ret, mbed_ret; + int ret; struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; - mbed_ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len); - if (mbed_ret < 0) + ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len); + if (ret < 0) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_read() return -0x%x", -ret); ret = -1; - else if (mbed_ret == 0) - ret = 0; - else - ret = mbed_ret; + } return ret; } int ssl_pm_send(SSL *ssl, const void *buffer, int len) { - int ret, mbed_ret; + int ret; struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; - mbed_ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len); - if (mbed_ret < 0) + ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len); + if (ret < 0) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_write() return -0x%x", -ret); ret = -1; - else if (mbed_ret == 0) - ret = 0; - else - ret = mbed_ret; + } return ret; } @@ -430,23 +447,28 @@ int x509_pm_show_info(X509 *x) return -1; buf = ssl_mem_malloc(X509_INFO_STRING_LENGTH); - if (!buf) - SSL_RET(failed1, ""); + if (!buf) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (buf)"); + goto no_mem; + } ret = mbedtls_x509_crt_info(buf, X509_INFO_STRING_LENGTH - 1, "", x509_crt); - if (ret <= 0) - SSL_RET(failed2, ""); + if (ret <= 0) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_info() return -0x%x", -ret); + goto mbedtls_err1; + } + buf[ret] = 0; ssl_mem_free(buf); - SSL_DEBUG(1, "%s", buf); + SSL_DEBUG(SSL_DEBUG_ON, "%s", buf); return 0; -failed2: +mbedtls_err1: ssl_mem_free(buf); -failed1: +no_mem: return -1; } @@ -455,8 +477,10 @@ int x509_pm_new(X509 *x, X509 *m_x) struct x509_pm *x509_pm; x509_pm = ssl_mem_zalloc(sizeof(struct x509_pm)); - if (!x509_pm) - SSL_RET(failed1, "ssl_mem_zalloc\n"); + if (!x509_pm) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm)"); + goto failed1; + } x->x509_pm = x509_pm; @@ -498,34 +522,38 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) if (!x509_pm->x509_crt) { x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt)); - if (!x509_pm->x509_crt) - SSL_RET(failed1, "ssl_mem_malloc\n"); + if (!x509_pm->x509_crt) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm->x509_crt)"); + goto no_mem; + } } load_buf = ssl_mem_malloc(len + 1); - if (!load_buf) - SSL_RET(failed2, "ssl_mem_malloc\n"); + if (!load_buf) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)"); + goto failed; + } ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; - DEBUG_LOAD_BUF_STRING(load_buf); - mbedtls_x509_crt_init(x509_pm->x509_crt); ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len + 1); ssl_mem_free(load_buf); - if (ret) - SSL_RET(failed2, "mbedtls_x509_crt_parse, return [-0x%x]\n", -ret); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_parse return -0x%x", -ret); + goto failed; + } return 0; -failed2: +failed: mbedtls_x509_crt_free(x509_pm->x509_crt); ssl_mem_free(x509_pm->x509_crt); x509_pm->x509_crt = NULL; -failed1: +no_mem: return -1; } @@ -574,34 +602,38 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) if (!pkey_pm->pkey) { pkey_pm->pkey = ssl_mem_malloc(sizeof(mbedtls_pk_context)); - if (!pkey_pm->pkey) - SSL_RET(failed1, "ssl_mem_malloc\n"); + if (!pkey_pm->pkey) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (pkey_pm->pkey)"); + goto no_mem; + } } load_buf = ssl_mem_malloc(len + 1); - if (!load_buf) - SSL_RET(failed2, "ssl_mem_malloc\n"); + if (!load_buf) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)"); + goto failed; + } ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; - DEBUG_LOAD_BUF_STRING(load_buf); - mbedtls_pk_init(pkey_pm->pkey); ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len + 1, NULL, 0); ssl_mem_free(load_buf); - if (ret) - SSL_RET(failed2, "mbedtls_pk_parse_key, return [-0x%x]\n", -ret); + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_pk_parse_key return -0x%x", -ret); + goto failed; + } return 0; -failed2: +failed: mbedtls_pk_free(pkey_pm->pkey); ssl_mem_free(pkey_pm->pkey); pkey_pm->pkey = NULL; -failed1: +no_mem: return -1; } @@ -619,11 +651,11 @@ long ssl_pm_get_verify_result(const SSL *ssl) struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; ret = mbedtls_ssl_get_verify_result(&ssl_pm->ssl); - - if (!ret) - verify_result = X509_V_OK; - else + if (ret) { + SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_get_verify_result() return -0x%x", -ret); verify_result = X509_V_ERR_UNSPECIFIED; + } else + verify_result = X509_V_OK; return verify_result; } diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c index ae3b849ca3..8c7a31338b 100644 --- a/components/openssl/platform/ssl_port.c +++ b/components/openssl/platform/ssl_port.c @@ -14,15 +14,10 @@ #include "ssl_port.h" -#ifdef ESP32_IDF_PLATFORM - -#include "string.h" -#include "malloc.h" - /*********************************************************************************************/ /********************************* SSL general interface *************************************/ -void* ssl_mem_zalloc(size_t size) +void *ssl_mem_zalloc(size_t size) { void *p = malloc(size); @@ -32,35 +27,3 @@ void* ssl_mem_zalloc(size_t size) return p; } -void *ssl_mem_malloc(size_t size) -{ - return malloc(size); -} - -void ssl_mem_free(void *p) -{ - free(p); -} - -void* ssl_memcpy(void *to, const void *from, size_t size) -{ - return memcpy(to, from, size); -} - -size_t ssl_strlen(const char *src) -{ - return strlen(src); -} - -void ssl_speed_up_enter(void) -{ - -} - -void ssl_speed_up_exit(void) -{ - -} - -#endif - diff --git a/components/partition_table/Makefile.projbuild b/components/partition_table/Makefile.projbuild index 5d1e726a86..4d548f7e2d 100644 --- a/components/partition_table/Makefile.projbuild +++ b/components/partition_table/Makefile.projbuild @@ -14,10 +14,12 @@ GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q # Has a matching value in bootloader_support esp_flash_partitions.h PARTITION_TABLE_OFFSET := 0x8000 +ifndef PARTITION_TABLE_CSV_PATH # Path to partition CSV file is relative to project path for custom # partition CSV files, but relative to component dir otherwise.$ PARTITION_TABLE_ROOT := $(call dequote,$(if $(CONFIG_PARTITION_TABLE_CUSTOM),$(PROJECT_PATH),$(COMPONENT_PATH))) PARTITION_TABLE_CSV_PATH := $(call dequote,$(abspath $(PARTITION_TABLE_ROOT)/$(subst $(quote),,$(CONFIG_PARTITION_TABLE_FILENAME)))) +endif PARTITION_TABLE_BIN := $(BUILD_DIR_BASE)/$(notdir $(PARTITION_TABLE_CSV_PATH:.csv=.bin)) diff --git a/components/partition_table/gen_esp32part.py b/components/partition_table/gen_esp32part.py index 0491204885..d57059f4ef 100755 --- a/components/partition_table/gen_esp32part.py +++ b/components/partition_table/gen_esp32part.py @@ -4,9 +4,12 @@ # # Converts partition tables to/from CSV and binary formats. # -# See the sdkng README.md file for details about how to use this tool. -import struct +# See http://esp-idf.readthedocs.io/en/latest/partition-tables.html for explanation of +# partition table structure and uses. import argparse +import os +import re +import struct import sys MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature @@ -144,7 +147,7 @@ class PartitionDefinition(object): # dictionary maps flag name (as used in CSV flags list, property name) # to bit set in flags words in binary format FLAGS = { - "encrypted" : 1 + "encrypted" : 0 } # add subtypes for the 16 OTA slot values ("ota_XXX, etc.") @@ -163,7 +166,13 @@ class PartitionDefinition(object): def from_csv(cls, line): """ Parse a line from the CSV """ line_w_defaults = line + ",,,," # lazy way to support default fields - fields = [ f.strip() for f in line_w_defaults.split(",") ] + def expand_vars(f): + f = os.path.expandvars(f) + m = re.match(r'(?>sys.stderr, e sys.exit(2) diff --git a/components/partition_table/test/test_partition.c b/components/partition_table/test/test_partition.c index a4288d8e1d..a268222802 100644 --- a/components/partition_table/test/test_partition.c +++ b/components/partition_table/test/test_partition.c @@ -26,7 +26,7 @@ TEST_CASE("Can read partition table", "[partition]") printf("%d\n", __builtin_clz(count)); } -TEST_CASE("Can write, read, mmap partition", "[partition]") +TEST_CASE("Can write, read, mmap partition", "[partition][ignore]") { const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL); TEST_ASSERT_NOT_NULL(p); diff --git a/components/sdmmc/test/test_sd.c b/components/sdmmc/test/test_sd.c index 6c2154817f..768fecc258 100644 --- a/components/sdmmc/test/test_sd.c +++ b/components/sdmmc/test/test_sd.c @@ -26,7 +26,7 @@ #include -TEST_CASE("can probe SD", "[sd]") +TEST_CASE("can probe SD", "[sd][ignore]") { sdmmc_host_t config = SDMMC_HOST_DEFAULT(); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); @@ -76,7 +76,7 @@ static void do_single_write_read_test(sdmmc_card_t* card, free(buffer); } -TEST_CASE("can write and read back blocks", "[sd]") +TEST_CASE("can write and read back blocks", "[sd][ignore]") { sdmmc_host_t config = SDMMC_HOST_DEFAULT(); config.max_freq_khz = SDMMC_FREQ_HIGHSPEED; diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index 983ff5d256..5e880ab493 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -41,6 +41,9 @@ static uint32_t s_flash_op_cache_state[2]; static SemaphoreHandle_t s_flash_op_mutex; static volatile bool s_flash_op_can_start = false; static volatile bool s_flash_op_complete = false; +#ifndef NDEBUG +static volatile int s_flash_op_cpu = -1; +#endif void spi_flash_init_lock() { @@ -85,6 +88,11 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() const uint32_t cpuid = xPortGetCoreID(); const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; +#ifndef NDEBUG + // For sanity check later: record the CPU which has started doing flash operation + assert(s_flash_op_cpu == -1); + s_flash_op_cpu = cpuid; +#endif if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { // Scheduler hasn't been started yet, it means that spi_flash API is being @@ -98,12 +106,13 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() // disable cache there and block other tasks from executing. s_flash_op_can_start = false; s_flash_op_complete = false; - esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void*) other_cpuid); + esp_err_t ret = esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void*) other_cpuid); + assert(ret == ESP_OK); while (!s_flash_op_can_start) { // Busy loop and wait for spi_flash_op_block_func to disable cache // on the other CPU } - // Disable scheduler on CPU cpuid + // Disable scheduler on the current CPU vTaskSuspendAll(); // This is guaranteed to run on CPU because the other CPU is now // occupied by highest priority task @@ -119,6 +128,11 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() { const uint32_t cpuid = xPortGetCoreID(); const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; +#ifndef NDEBUG + // Sanity check: flash operation ends on the same CPU as it has started + assert(cpuid == s_flash_op_cpu); + s_flash_op_cpu = -1; +#endif // Re-enable cache on this CPU spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]); @@ -132,13 +146,21 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() } else { // Signal to spi_flash_op_block_task that flash operation is complete s_flash_op_complete = true; - // Resume tasks on the current CPU + } + // Re-enable non-iram interrupts + esp_intr_noniram_enable(); + + // Resume tasks on the current CPU, if the scheduler has started. + // NOTE: enabling non-IRAM interrupts has to happen before this, + // because once the scheduler has started, due to preemption the + // current task can end up being moved to the other CPU. + // But esp_intr_noniram_enable has to be called on the same CPU which + // called esp_intr_noniram_disable + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { xTaskResumeAll(); } // Release API lock spi_flash_op_unlock(); - // Re-enable non-iram interrupts - esp_intr_noniram_enable(); } void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os() @@ -183,16 +205,16 @@ void spi_flash_op_unlock() void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() { - esp_intr_noniram_disable(); spi_flash_op_lock(); + esp_intr_noniram_disable(); spi_flash_disable_cache(0, &s_flash_op_cache_state[0]); } void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() { spi_flash_restore_cache(0, s_flash_op_cache_state[0]); - spi_flash_op_unlock(); esp_intr_noniram_enable(); + spi_flash_op_unlock(); } void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os() diff --git a/components/spi_flash/cache_utils.h b/components/spi_flash/cache_utils.h index 598b8fba77..9cd9ad6b49 100644 --- a/components/spi_flash/cache_utils.h +++ b/components/spi_flash/cache_utils.h @@ -48,4 +48,12 @@ void spi_flash_disable_interrupts_caches_and_other_cpu_no_os(); // This function is implied to be called when other CPU is not running or running code from IRAM. void spi_flash_enable_interrupts_caches_no_os(); +// Mark the pages containing a flash region as having been +// erased or written to. This means the flash cache needs +// to be evicted before these pages can be flash_mmap()ed again, +// as they may contain stale data +// +// Only call this while holding spi_flash_op_lock() +void spi_flash_mark_modified_region(uint32_t start_addr, uint32_t length); + #endif //ESP_SPI_FLASH_CACHE_UTILS_H diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index 15f75f3634..f8d2e3297d 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -28,6 +28,7 @@ #include "esp_ipc.h" #include "esp_attr.h" #include "esp_spi_flash.h" +#include "esp_flash_encrypt.h" #include "esp_log.h" #include "cache_utils.h" @@ -39,13 +40,23 @@ #define REGIONS_COUNT 4 #define PAGES_PER_REGION 64 -#define FLASH_PAGE_SIZE 0x10000 #define INVALID_ENTRY_VAL 0x100 #define VADDR0_START_ADDR 0x3F400000 #define VADDR1_START_ADDR 0x40000000 #define VADDR1_FIRST_USABLE_ADDR 0x400D0000 -#define PRO_IRAM0_FIRST_USABLE_PAGE ((VADDR1_FIRST_USABLE_ADDR - VADDR1_START_ADDR) / FLASH_PAGE_SIZE + 64) +#define PRO_IRAM0_FIRST_USABLE_PAGE ((VADDR1_FIRST_USABLE_ADDR - VADDR1_START_ADDR) / SPI_FLASH_MMU_PAGE_SIZE + 64) +/* Ensure pages in a region haven't been marked as written via + spi_flash_mark_modified_region(). If the page has + been written, flush the entire flash cache before returning. + + This ensures stale cache entries are never read after fresh calls + to spi_flash_mmap(), while keeping the number of cache flushes to a + minimum. + + Returns true if cache was flushed. +*/ +static bool spi_flash_ensure_unmodified_region(size_t start_addr, size_t length); typedef struct mmap_entry_{ uint32_t handle; @@ -81,6 +92,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ const void** out_ptr, spi_flash_mmap_handle_t* out_handle) { esp_err_t ret; + bool did_flush, need_flush = false; mmap_entry_t* new_entry = (mmap_entry_t*) malloc(sizeof(mmap_entry_t)); if (new_entry == 0) { return ESP_ERR_NO_MEM; @@ -91,7 +103,11 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ if (src_addr + size > g_rom_flashchip.chip_size) { return ESP_ERR_INVALID_ARG; } + spi_flash_disable_interrupts_caches_and_other_cpu(); + + did_flush = spi_flash_ensure_unmodified_region(src_addr, size); + if (s_mmap_page_refcnt[0] == 0) { spi_flash_mmap_init(); } @@ -111,8 +127,8 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ region_addr = VADDR1_FIRST_USABLE_ADDR; } // region which should be mapped - int phys_page = src_addr / FLASH_PAGE_SIZE; - int page_count = (size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE; + int phys_page = src_addr / SPI_FLASH_MMU_PAGE_SIZE; + int page_count = (size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE; // The following part searches for a range of MMU entries which can be used. // Algorithm is essentially naïve strstr algorithm, except that unused MMU // entries are treated as wildcards. @@ -147,8 +163,11 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ (DPORT_PRO_FLASH_MMU_TABLE[i] == entry_val && DPORT_APP_FLASH_MMU_TABLE[i] == entry_val)); if (s_mmap_page_refcnt[i] == 0) { - DPORT_PRO_FLASH_MMU_TABLE[i] = entry_val; - DPORT_APP_FLASH_MMU_TABLE[i] = entry_val; + if (DPORT_PRO_FLASH_MMU_TABLE[i] != entry_val || DPORT_APP_FLASH_MMU_TABLE[i] != entry_val) { + DPORT_PRO_FLASH_MMU_TABLE[i] = entry_val; + DPORT_APP_FLASH_MMU_TABLE[i] = entry_val; + need_flush = true; + } } ++s_mmap_page_refcnt[i]; } @@ -158,9 +177,21 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_ new_entry->count = page_count; new_entry->handle = ++s_mmap_last_handle; *out_handle = new_entry->handle; - *out_ptr = (void*) (region_addr + start * FLASH_PAGE_SIZE); + *out_ptr = (void*) (region_addr + start * SPI_FLASH_MMU_PAGE_SIZE); ret = ESP_OK; } + + /* This is a temporary fix for an issue where some + encrypted cache reads may see stale data. + + Working on a long term fix that doesn't require invalidating + entire cache. + */ + if (esp_flash_encryption_enabled() && !did_flush && need_flush) { + Cache_Flush(0); + Cache_Flush(1); + } + spi_flash_enable_interrupts_caches_and_other_cpu(); if (*out_ptr == NULL) { free(new_entry); @@ -212,3 +243,65 @@ void spi_flash_mmap_dump() } } } + +/* 256-bit (up to 16MB of 64KB pages) bitset of all flash pages + that have been written to since last cache flush. + + Before mmaping a page, need to flush caches if that page has been + written to. + + Note: It's possible to do some additional performance tweaks to + this algorithm, as we actually only need to flush caches if a page + was first mmapped, then written to, then is about to be mmaped a + second time. This is a fair bit more complex though, so unless + there's an access pattern that this would significantly boost then + it's probably not worth it. +*/ +static uint32_t written_pages[256/32]; + +static bool update_written_pages(size_t start_addr, size_t length, bool mark); + +void IRAM_ATTR spi_flash_mark_modified_region(size_t start_addr, size_t length) +{ + update_written_pages(start_addr, length, true); +} + +static IRAM_ATTR bool spi_flash_ensure_unmodified_region(size_t start_addr, size_t length) +{ + return update_written_pages(start_addr, length, false); +} + +/* generic implementation for the previous two functions */ +static inline IRAM_ATTR bool update_written_pages(size_t start_addr, size_t length, bool mark) +{ + /* align start_addr & length to full MMU pages */ + uint32_t page_start_addr = start_addr & ~(SPI_FLASH_MMU_PAGE_SIZE-1); + length += (start_addr - page_start_addr); + length = (length + SPI_FLASH_MMU_PAGE_SIZE - 1) & ~(SPI_FLASH_MMU_PAGE_SIZE-1); + for (uint32_t addr = page_start_addr; addr < page_start_addr + length; addr += SPI_FLASH_MMU_PAGE_SIZE) { + int page = addr / SPI_FLASH_MMU_PAGE_SIZE; + if (page >= 256) { + return false; /* invalid address */ + } + + int idx = page / 32; + uint32_t bit = 1 << (page % 32); + + if (mark) { + written_pages[idx] |= bit; + } else if (written_pages[idx] & bit) { + /* it is tempting to write a version of this that only + flushes each CPU's cache as needed. However this is + tricky because mmaped memory can be used on un-pinned + cores, or the pointer passed between CPUs. + */ + Cache_Flush(0); +#ifndef CONFIG_FREERTOS_UNICORE + Cache_Flush(1); +#endif + bzero(written_pages, sizeof(written_pages)); + return true; + } + } + return false; +} diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index fffe487bd1..324c02a3d0 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -61,13 +61,17 @@ static spi_flash_counters_t s_flash_stats; static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc); const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_default_ops = { - .start = spi_flash_disable_interrupts_caches_and_other_cpu, - .end = spi_flash_enable_interrupts_caches_and_other_cpu + .start = spi_flash_disable_interrupts_caches_and_other_cpu, + .end = spi_flash_enable_interrupts_caches_and_other_cpu, + .op_lock = spi_flash_op_lock, + .op_unlock = spi_flash_op_unlock }; const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_no_os_ops = { - .start = spi_flash_disable_interrupts_caches_and_other_cpu_no_os, - .end = spi_flash_enable_interrupts_caches_no_os + .start = spi_flash_disable_interrupts_caches_and_other_cpu_no_os, + .end = spi_flash_enable_interrupts_caches_no_os, + .op_lock = 0, + .op_unlock = 0 }; static const spi_flash_guard_funcs_t *s_flash_guard_ops; @@ -80,17 +84,17 @@ void spi_flash_init() #endif } -void spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs) +void IRAM_ATTR spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs) { s_flash_guard_ops = funcs; } -size_t spi_flash_get_chip_size() +size_t IRAM_ATTR spi_flash_get_chip_size() { return g_rom_flashchip.chip_size; } -SpiFlashOpResult IRAM_ATTR spi_flash_unlock() +static SpiFlashOpResult IRAM_ATTR spi_flash_unlock() { static bool unlocked = false; if (!unlocked) { @@ -103,16 +107,32 @@ SpiFlashOpResult IRAM_ATTR spi_flash_unlock() return SPI_FLASH_RESULT_OK; } -static inline void spi_flash_guard_start() +static inline void IRAM_ATTR spi_flash_guard_start() { - if (s_flash_guard_ops) + if (s_flash_guard_ops && s_flash_guard_ops->start) { s_flash_guard_ops->start(); + } } -static inline void spi_flash_guard_end() +static inline void IRAM_ATTR spi_flash_guard_end() { - if (s_flash_guard_ops) + if (s_flash_guard_ops && s_flash_guard_ops->end) { s_flash_guard_ops->end(); + } +} + +static inline void IRAM_ATTR spi_flash_guard_op_lock() +{ + if (s_flash_guard_ops && s_flash_guard_ops->op_lock) { + s_flash_guard_ops->op_lock(); + } +} + +static inline void IRAM_ATTR spi_flash_guard_op_unlock() +{ + if (s_flash_guard_ops && s_flash_guard_ops->op_unlock) { + s_flash_guard_ops->op_unlock(); + } } esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) @@ -182,7 +202,9 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) size_t mid_size = (size - left_size) & ~3U; size_t right_off = left_size + mid_size; size_t right_size = size - mid_size - left_size; + spi_flash_guard_start(); rc = spi_flash_unlock(); + spi_flash_guard_end(); if (rc != SPI_FLASH_RESULT_OK) { goto out; } @@ -248,35 +270,70 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) } out: COUNTER_STOP(write); + + spi_flash_guard_op_lock(); + spi_flash_mark_modified_region(dst, size); + spi_flash_guard_op_unlock(); + return spi_flash_translate_rc(rc); } esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size) { - if ((dest_addr % 32) != 0) { + const uint8_t *ssrc = (const uint8_t *)src; + if ((dest_addr % 16) != 0) { return ESP_ERR_INVALID_ARG; } - if ((size % 32) != 0) { + if ((size % 16) != 0) { return ESP_ERR_INVALID_SIZE; } - if ((uint32_t) src < 0x3ff00000) { - // if source address is in DROM, we won't be able to read it - // from within SPIWrite - // TODO: consider buffering source data using heap and writing it anyway? - return ESP_ERR_INVALID_ARG; - } + COUNTER_START(); spi_flash_disable_interrupts_caches_and_other_cpu(); SpiFlashOpResult rc; + spi_flash_guard_start(); rc = spi_flash_unlock(); + spi_flash_guard_end(); + spi_flash_enable_interrupts_caches_and_other_cpu(); + if (rc == SPI_FLASH_RESULT_OK) { /* SPI_Encrypt_Write encrypts data in RAM as it writes, so copy to a temporary buffer - 32 bytes at a time. + + Each call to SPI_Encrypt_Write takes a 32 byte "row" of + data to encrypt, and each row is two 16 byte AES blocks + that share a key (as derived from flash address). */ - uint32_t encrypt_buf[32/sizeof(uint32_t)]; - for (size_t i = 0; i < size; i += 32) { - memcpy(encrypt_buf, ((const uint8_t *)src) + i, 32); - rc = SPI_Encrypt_Write((uint32_t) dest_addr + i, encrypt_buf, 32); + uint8_t encrypt_buf[32] __attribute__((aligned(4))); + uint32_t row_size; + for (size_t i = 0; i < size; i += row_size) { + uint32_t row_addr = dest_addr + i; + if (i == 0 && (row_addr % 32) != 0) { + /* writing to second block of a 32 byte row */ + row_size = 16; + row_addr -= 16; + /* copy to second block in buffer */ + memcpy(encrypt_buf + 16, ssrc + i, 16); + /* decrypt the first block from flash, will reencrypt to same bytes */ + spi_flash_read_encrypted(row_addr, encrypt_buf, 16); + } + else if (size - i == 16) { + /* 16 bytes left, is first block of a 32 byte row */ + row_size = 16; + /* copy to first block in buffer */ + memcpy(encrypt_buf, ssrc + i, 16); + /* decrypt the second block from flash, will reencrypt to same bytes */ + spi_flash_read_encrypted(row_addr + 16, encrypt_buf + 16, 16); + } + else { + /* Writing a full 32 byte row (2 blocks) */ + row_size = 32; + memcpy(encrypt_buf, ssrc + i, 32); + } + + spi_flash_disable_interrupts_caches_and_other_cpu(); + rc = SPI_Encrypt_Write(row_addr, (uint32_t *)encrypt_buf, 32); + spi_flash_enable_interrupts_caches_and_other_cpu(); if (rc != SPI_FLASH_RESULT_OK) { break; } @@ -284,6 +341,11 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, bzero(encrypt_buf, sizeof(encrypt_buf)); } COUNTER_ADD_BYTES(write, size); + + spi_flash_guard_op_lock(); + spi_flash_mark_modified_region(dest_addr, size); + spi_flash_guard_op_unlock(); + return spi_flash_translate_rc(rc); } @@ -379,7 +441,32 @@ out: return spi_flash_translate_rc(rc); } -static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc) +esp_err_t IRAM_ATTR spi_flash_read_encrypted(size_t src, void *dstv, size_t size) +{ + if (src + size > g_rom_flashchip.chip_size) { + return ESP_ERR_INVALID_SIZE; + } + if (size == 0) { + return ESP_OK; + } + + esp_err_t err; + const uint8_t *map; + spi_flash_mmap_handle_t map_handle; + size_t map_src = src & ~(SPI_FLASH_MMU_PAGE_SIZE-1); + size_t map_size = size + (src - map_src); + + err = spi_flash_mmap(map_src, map_size, SPI_FLASH_MMAP_DATA, (const void **)&map, &map_handle); + if (err != ESP_OK) { + return err; + } + memcpy(dstv, map + (src - map_src), size); + spi_flash_munmap(map_handle); + return err; +} + + +static esp_err_t IRAM_ATTR spi_flash_translate_rc(SpiFlashOpResult rc) { switch (rc) { case SPI_FLASH_RESULT_OK: diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index b149e10234..28f8551dcb 100644 --- a/components/spi_flash/include/esp_partition.h +++ b/components/spi_flash/include/esp_partition.h @@ -191,6 +191,13 @@ esp_err_t esp_partition_read(const esp_partition_t* partition, * Before writing data to flash, corresponding region of flash needs to be erased. * This can be done using esp_partition_erase_range function. * + * Partitions marked with an encryption flag will automatically be + * written via the spi_flash_write_encrypted() function. If writing to + * an encrypted partition, all write offsets and lengths must be + * multiples of 16 bytes. See the spi_flash_write_encrypted() function + * for more details. Unencrypted partitions do not have this + * restriction. + * * @param partition Pointer to partition structure obtained using * esp_partition_find_first or esp_partition_get. * Must be non-NULL. diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index bf897e8995..060d598ec0 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -31,6 +31,8 @@ extern "C" { #define SPI_FLASH_SEC_SIZE 4096 /**< SPI Flash sector size */ +#define SPI_FLASH_MMU_PAGE_SIZE 0x10000 /**< Flash cache MMU mapping page size */ + /** * @brief Initialize SPI flash access driver * @@ -92,14 +94,18 @@ esp_err_t spi_flash_write(size_t dest_addr, const void *src, size_t size); * * @note Flash encryption must be enabled for this function to work. * - * @note Address in flash, dest, has to be 32-byte aligned. + * @note Flash encryption must be enabled when calling this function. + * If flash encryption is disabled, the function returns + * ESP_ERR_INVALID_STATE. Use esp_flash_encryption_enabled() + * function to determine if flash encryption is enabled. * - * @note If source address is in DROM, this function will return - * ESP_ERR_INVALID_ARG. + * @note Both dest_addr and size must be multiples of 16 bytes. For + * absolute best performance, both dest_addr and size arguments should + * be multiples of 32 bytes. * - * @param dest_addr destination address in Flash. Must be a multiple of 32 bytes. + * @param dest_addr destination address in Flash. Must be a multiple of 16 bytes. * @param src pointer to the source buffer. - * @param size length of data, in bytes. Must be a multiple of 32 bytes. + * @param size length of data, in bytes. Must be a multiple of 16 bytes. * * @return esp_err_t */ @@ -116,6 +122,23 @@ esp_err_t spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t si */ esp_err_t spi_flash_read(size_t src_addr, void *dest, size_t size); + +/** + * @brief Read data from Encrypted Flash. + * + * If flash encryption is enabled, this function will transparently decrypt data as it is read. + * If flash encryption is not enabled, this function behaves the same as spi_flash_read(). + * + * See esp_flash_encryption_enabled() for a function to check if flash encryption is enabled. + * + * @param src source address of the data in Flash. + * @param dest pointer to the destination buffer + * @param size length of data + * + * @return esp_err_t + */ +esp_err_t spi_flash_read_encrypted(size_t src, void *dest, size_t size); + /** * @brief Enumeration which specifies memory space requested in an mmap call */ @@ -140,7 +163,8 @@ typedef uint32_t spi_flash_mmap_handle_t; * page allocation, use spi_flash_mmap_dump function. * * @param src_addr Physical address in flash where requested region starts. - * This address *must* be aligned to 64kB boundary. + * This address *must* be aligned to 64kB boundary + * (SPI_FLASH_MMU_PAGE_SIZE). * @param size Size of region which has to be mapped. This size will be rounded * up to a 64k boundary. * @param memory Memory space where the region should be mapped @@ -181,16 +205,44 @@ typedef void (*spi_flash_guard_start_func_t)(void); * @brief SPI flash critical section exit function. */ typedef void (*spi_flash_guard_end_func_t)(void); +/** + * @brief SPI flash operation lock function. + */ +typedef void (*spi_flash_op_lock_func_t)(void); +/** + * @brief SPI flash operation unlock function. + */ +typedef void (*spi_flash_op_unlock_func_t)(void); /** - * Structure holding SPI flash access critical section management functions + * Structure holding SPI flash access critical sections management functions. + * + * Flash API uses two types of flash access management functions: + * 1) Functions which prepare/restore flash cache and interrupts before calling + * appropriate ROM functions (SPIWrite, SPIRead and SPIEraseBlock): + * - 'start' function should disables flash cache and non-IRAM interrupts and + * is invoked before the call to one of ROM function above. + * - 'end' function should restore state of flash cache and non-IRAM interrupts and + * is invoked after the call to one of ROM function above. + * 2) Functions which synchronizes access to internal data used by flash API. + * This functions are mostly intended to synchronize access to flash API internal data + * in multithreaded environment and use OS primitives: + * - 'op_lock' locks access to flash API internal data. + * - 'op_unlock' unlocks access to flash API internal data. + * Different versions of the guarding functions should be used depending on the context of + * execution (with or without functional OS). In normal conditions when flash API is called + * from task the functions use OS primitives. When there is no OS at all or when + * it is not guaranteed that OS is functional (accessing flash from exception handler) these + * functions cannot use OS primitives or even does not need them (multithreaded access is not possible). * * @note Structure and corresponding guard functions should not reside in flash. * For example structure can be placed in DRAM and functions in IRAM sections. */ typedef struct { - spi_flash_guard_start_func_t start; /**< critical section start func */ - spi_flash_guard_end_func_t end; /**< critical section end func */ + spi_flash_guard_start_func_t start; /**< critical section start func */ + spi_flash_guard_end_func_t end; /**< critical section end func */ + spi_flash_op_lock_func_t op_lock; /**< flash access API lock func */ + spi_flash_op_unlock_func_t op_unlock; /**< flash access API unlock func */ } spi_flash_guard_funcs_t; /** diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 490efbb32c..76036b305e 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -166,10 +166,14 @@ static esp_err_t load_partitions() item->info.type = it->type; item->info.subtype = it->subtype; item->info.encrypted = it->flags & PART_FLAG_ENCRYPTED; - if (esp_flash_encryption_enabled() && it->type == PART_TYPE_APP) { - /* All app partitions are encrypted if encryption is turned on */ + if (esp_flash_encryption_enabled() && ( + it->type == PART_TYPE_APP + || (it->type == PART_TYPE_DATA && it->subtype == PART_SUBTYPE_DATA_OTA))) { + /* If encryption is turned on, all app partitions and OTA data + are always encrypted */ item->info.encrypted = true; } + // it->label may not be zero-terminated strncpy(item->info.label, (const char*) it->label, sizeof(it->label)); item->info.label[sizeof(it->label)] = 0; @@ -230,10 +234,6 @@ esp_err_t esp_partition_write(const esp_partition_t* partition, size_t dst_offset, const void* src, size_t size) { assert(partition != NULL); - //todo : need add ecrypt write support ,size must be 32-bytes align - if(partition->encrypted == true) { - return ESP_FAIL; - } if (dst_offset > partition->size) { return ESP_ERR_INVALID_ARG; } diff --git a/components/spi_flash/test/test_config.h b/components/spi_flash/test/test_config.h new file mode 100644 index 0000000000..45e73661bb --- /dev/null +++ b/components/spi_flash/test/test_config.h @@ -0,0 +1,24 @@ +// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Common header for SPI flash test data +#pragma once + +/* Define a region of flash we can mess up for testing... + + This is pretty ugly, better to do something with a partition but + this is OK for now. + */ +#define TEST_REGION_START 0x180000 +#define TEST_REGION_END 0x1E0000 diff --git a/components/spi_flash/test/test_flash_encryption.c b/components/spi_flash/test/test_flash_encryption.c new file mode 100644 index 0000000000..b8d8018ae4 --- /dev/null +++ b/components/spi_flash/test/test_flash_encryption.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "test_config.h" + +static void test_encrypted_write(size_t offset, const uint8_t *data, size_t length); +static void verify_erased_flash(size_t offset, size_t length); + +TEST_CASE("test 16 byte encrypted writes", "[spi_flash]") +{ + if (!esp_flash_encryption_enabled()) { + TEST_IGNORE_MESSAGE("flash encryption disabled, skipping spi_flash_write_encrypted() tests"); + } + + TEST_ASSERT_EQUAL_HEX(ESP_OK, + spi_flash_erase_sector(TEST_REGION_START / SPI_FLASH_SEC_SIZE)); + + uint8_t fortyeight_bytes[0x30]; // 0, 1, 2, 3, 4... 47 + for(int i = 0; i < sizeof(fortyeight_bytes); i++) { + fortyeight_bytes[i] = i; + } + + /* Verify unaligned start or length fails */ + TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, + spi_flash_write_encrypted(TEST_REGION_START+1, fortyeight_bytes, 32)); + + TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_SIZE, + spi_flash_write_encrypted(TEST_REGION_START, fortyeight_bytes, 15)); + + /* ensure nothing happened to the flash yet */ + verify_erased_flash(TEST_REGION_START, 0x20); + + /* Write 32 byte block, this is the "normal" encrypted write */ + test_encrypted_write(TEST_REGION_START, fortyeight_bytes, 0x20); + verify_erased_flash(TEST_REGION_START + 0x20, 0x20); + + /* Slip in an unaligned spi_flash_read_encrypted() test */ + uint8_t buf[0x10]; + spi_flash_read_encrypted(TEST_REGION_START+0x10, buf, 0x10); + TEST_ASSERT_EQUAL_HEX8_ARRAY(fortyeight_bytes+0x10, buf, 16); + + /* Write 16 bytes unaligned */ + test_encrypted_write(TEST_REGION_START + 0x30, fortyeight_bytes, 0x10); + /* the 16 byte regions before and after the 16 bytes we just wrote should still be 0xFF */ + verify_erased_flash(TEST_REGION_START + 0x20, 0x10); + verify_erased_flash(TEST_REGION_START + 0x40, 0x10); + + /* Write 48 bytes starting at a 32-byte aligned offset */ + test_encrypted_write(TEST_REGION_START + 0x40, fortyeight_bytes, 0x30); + /* 16 bytes after this write should still be 0xFF -unencrypted- */ + verify_erased_flash(TEST_REGION_START + 0x70, 0x10); + + /* Write 48 bytes starting at a 16-byte aligned offset */ + test_encrypted_write(TEST_REGION_START + 0x90, fortyeight_bytes, 0x30); + /* 16 bytes after this write should still be 0xFF -unencrypted- */ + verify_erased_flash(TEST_REGION_START + 0x120, 0x10); +} + +static void test_encrypted_write(size_t offset, const uint8_t *data, size_t length) +{ + uint8_t readback[length]; + printf("encrypt %d bytes at 0x%x\n", length, offset); + TEST_ASSERT_EQUAL_HEX(ESP_OK, + spi_flash_write_encrypted(offset, data, length)); + + TEST_ASSERT_EQUAL_HEX(ESP_OK, + spi_flash_read_encrypted(offset, readback, length)); + + TEST_ASSERT_EQUAL_HEX8_ARRAY(data, readback, length); +} + +static void verify_erased_flash(size_t offset, size_t length) +{ + uint8_t readback[length]; + printf("verify erased 0x%x - 0x%x\n", offset, offset + length); + TEST_ASSERT_EQUAL_HEX(ESP_OK, + spi_flash_read(offset, readback, length)); + for (int i = 0; i < length; i++) { + char message[32]; + sprintf(message, "unerased flash @ 0x%08x", offset + i); + TEST_ASSERT_EQUAL_HEX_MESSAGE(0xFF, readback[i], message); + } +} + diff --git a/components/spi_flash/test/test_mmap.c b/components/spi_flash/test/test_mmap.c index d3d16802ea..464a876428 100644 --- a/components/spi_flash/test/test_mmap.c +++ b/components/spi_flash/test/test_mmap.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,14 +8,17 @@ #include #include #include +#include -uint32_t buffer[1024]; +#include "test_config.h" +static uint32_t buffer[1024]; + +/* read-only region used for mmap tests */ static const uint32_t start = 0x100000; static const uint32_t end = 0x200000; - TEST_CASE("Prepare data for mmap tests", "[mmap]") { srand(0); @@ -81,3 +85,49 @@ TEST_CASE("Can mmap into data address space", "[mmap]") printf("Unmapping handle3\n"); spi_flash_munmap(handle3); } + +TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") +{ + spi_flash_mmap_handle_t handle1; + const void *ptr1; + + const size_t test_size = 128; + + if (esp_flash_encryption_enabled()) { + TEST_IGNORE_MESSAGE("flash encryption enabled, spi_flash_write_encrypted() test won't pass as-is"); + } + + ESP_ERROR_CHECK( spi_flash_erase_sector(TEST_REGION_START / SPI_FLASH_SEC_SIZE) ); + + /* map erased test region to ptr1 */ + ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); + printf("mmap_res ptr1: handle=%d ptr=%p\n", handle1, ptr1); + + /* verify it's all 0xFF */ + for (int i = 0; i < test_size; i++) { + TEST_ASSERT_EQUAL_HEX(0xFF, ((uint8_t *)ptr1)[i]); + } + + /* unmap the erased region */ + spi_flash_munmap(handle1); + + /* write flash region to 0xEE */ + uint8_t buf[test_size]; + memset(buf, 0xEE, test_size); + ESP_ERROR_CHECK( spi_flash_write(TEST_REGION_START, buf, test_size) ); + + /* re-map the test region at ptr1. + + this is a fresh mmap call so should trigger a cache flush, + ensuring we see the updated flash. + */ + ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); + printf("mmap_res ptr1 #2: handle=%d ptr=%p\n", handle1, ptr1); + + /* assert that ptr1 now maps to the new values on flash, + ie contents of buf array. + */ + TEST_ASSERT_EQUAL_HEX8_ARRAY(buf, ptr1, test_size); + + spi_flash_munmap(handle1); +} diff --git a/components/spi_flash/test/test_read_write.c b/components/spi_flash/test/test_read_write.c index c9067463e4..37edbbb944 100644 --- a/components/spi_flash/test/test_read_write.c +++ b/components/spi_flash/test/test_read_write.c @@ -27,8 +27,10 @@ #include "soc/timer_group_struct.h" #include "soc/timer_group_reg.h" +#include "test_config.h" + /* Base offset in flash for tests. */ -#define FLASH_BASE 0x120000 +#define FLASH_BASE TEST_REGION_START #ifndef CONFIG_SPI_FLASH_MINIMAL_TEST #define CONFIG_SPI_FLASH_MINIMAL_TEST 1 diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index 330e37bb82..597568ec6a 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -7,86 +7,85 @@ #include #include +#include "test_config.h" + struct flash_test_ctx { - uint32_t offset[2]; - bool fail[2]; + uint32_t offset; + bool fail; SemaphoreHandle_t done; }; static void flash_test_task(void *arg) { - const uint32_t coreid = xPortGetCoreID(); - ets_printf("t%d\n", coreid); struct flash_test_ctx *ctx = (struct flash_test_ctx *) arg; vTaskDelay(100 / portTICK_PERIOD_MS); - const uint32_t sector = ctx->offset[coreid]; - ets_printf("es%d\n", coreid); + const uint32_t sector = ctx->offset; + printf("t%d\n", sector); + printf("es%d\n", sector); if (spi_flash_erase_sector(sector) != ESP_OK) { - ctx->fail[coreid] = true; - ets_printf("Erase failed\r\n"); + ctx->fail = true; + printf("Erase failed\r\n"); xSemaphoreGive(ctx->done); vTaskDelete(NULL); } - ets_printf("ed%d\n", coreid); + printf("ed%d\n", sector); vTaskDelay(0 / portTICK_PERIOD_MS); uint32_t val = 0xabcd1234; - const uint32_t n = 4096; - for (uint32_t offset = 0; offset < n; offset += 4) { + for (uint32_t offset = 0; offset < SPI_FLASH_SEC_SIZE; offset += 4) { if (spi_flash_write(sector * SPI_FLASH_SEC_SIZE + offset, (const uint8_t *) &val, 4) != ESP_OK) { - ets_printf("Write failed at offset=%d\r\n", offset); - ctx->fail[coreid] = true; + printf("Write failed at offset=%d\r\n", offset); + ctx->fail = true; break; } } - ets_printf("wd%d\n", coreid); + printf("wd%d\n", sector); vTaskDelay(0 / portTICK_PERIOD_MS); uint32_t val_read; - for (uint32_t offset = 0; offset < n; offset += 4) { + for (uint32_t offset = 0; offset < SPI_FLASH_SEC_SIZE; offset += 4) { if (spi_flash_read(sector * SPI_FLASH_SEC_SIZE + offset, (uint8_t *) &val_read, 4) != ESP_OK) { - ets_printf("Read failed at offset=%d\r\n", offset); - ctx->fail[coreid] = true; + printf("Read failed at offset=%d\r\n", offset); + ctx->fail = true; break; } if (val_read != val) { - ets_printf("Read invalid value=%08x at offset=%d\r\n", val_read, offset); - ctx->fail[coreid] = true; + printf("Read invalid value=%08x at offset=%d\r\n", val_read, offset); + ctx->fail = true; break; } } - ets_printf("td%d\n", coreid); + printf("td%d\n", sector); xSemaphoreGive(ctx->done); vTaskDelete(NULL); } -TEST_CASE("flash write and erase work both on PRO CPU and on APP CPU", "[spi_flash]") +TEST_CASE("flash write and erase work both on PRO CPU and on APP CPU", "[spi_flash][ignore]") { - TaskHandle_t procpu_task; - TaskHandle_t appcpu_task; - struct flash_test_ctx ctx; + SemaphoreHandle_t done = xSemaphoreCreateCounting(4, 0); + struct flash_test_ctx ctx[] = { + { .offset = 0x100 + 6, .done = done }, + { .offset = 0x100 + 7, .done = done }, + { .offset = 0x100 + 8, .done = done }, +#ifndef CONFIG_FREERTOS_UNICORE + { .offset = 0x100 + 9, .done = done } +#endif + }; - ctx.offset[0] = 6; - ctx.offset[1] = 7; - ctx.fail[0] = 0; - ctx.fail[1] = 0; - ctx.done = xSemaphoreCreateBinary(); + xTaskCreatePinnedToCore(flash_test_task, "t0", 2048, &ctx[0], 3, NULL, 0); + xTaskCreatePinnedToCore(flash_test_task, "t1", 2048, &ctx[1], 3, NULL, tskNO_AFFINITY); + xTaskCreatePinnedToCore(flash_test_task, "t2", 2048, &ctx[2], 3, NULL, tskNO_AFFINITY); +#ifndef CONFIG_FREERTOS_UNICORE + xTaskCreatePinnedToCore(flash_test_task, "t3", 2048, &ctx[3], 3, NULL, 1); +#endif - xTaskCreatePinnedToCore(flash_test_task, "1", 2048, &ctx, 3, &procpu_task, 0); - if (portNUM_PROCESSORS == 2) { - xTaskCreatePinnedToCore(flash_test_task, "2", 2048, &ctx, 3, &appcpu_task, 1); - } - - xSemaphoreTake(ctx.done, portMAX_DELAY); - if (portNUM_PROCESSORS == 2) { - xSemaphoreTake(ctx.done, portMAX_DELAY); - } - - TEST_ASSERT_EQUAL(false, ctx.fail[0]); - if (portNUM_PROCESSORS == 2) { - TEST_ASSERT_EQUAL(false, ctx.fail[1]); + const size_t task_count = sizeof(ctx)/sizeof(ctx[0]); + for (int i = 0; i < task_count; ++i) { + xSemaphoreTake(done, portMAX_DELAY); + TEST_ASSERT_FALSE(ctx[i].fail); } + vSemaphoreDelete(done); } diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index b2725e3447..40f235d545 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -85,7 +85,7 @@ esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_a if (dhcps_status == TCPIP_ADAPTER_DHCP_INIT) { dhcps_start(esp_netif[tcpip_if], ip_info->ip); - printf("dhcp server start:(ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR ")\n", + TCPIP_ADAPTER_DEBUG("dhcp server start:(ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR ")\n", IP2STR(&ip_info->ip), IP2STR(&ip_info->netmask), IP2STR(&ip_info->gw)); dhcps_status = TCPIP_ADAPTER_DHCP_STARTED; diff --git a/components/ulp/test/test_ulp.c b/components/ulp/test/test_ulp.c index 854eb3ee20..f04178623c 100644 --- a/components/ulp/test/test_ulp.c +++ b/components/ulp/test/test_ulp.c @@ -64,7 +64,7 @@ TEST_CASE("ulp add test", "[ulp]") TEST_ASSERT_EQUAL(10 + 11, RTC_SLOW_MEM[18] & 0xffff); } -TEST_CASE("ulp branch test", "[ulp]") +TEST_CASE("ulp branch test", "[ulp][ignore]") { assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); @@ -95,7 +95,7 @@ TEST_CASE("ulp branch test", "[ulp]") TEST_ASSERT_EQUAL(0, RTC_SLOW_MEM[64]); } -TEST_CASE("ulp wakeup test", "[ulp]") +TEST_CASE("ulp wakeup test", "[ulp][ignore]") { assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); @@ -121,7 +121,7 @@ TEST_CASE("ulp wakeup test", "[ulp]") esp_deep_sleep_start(); } -TEST_CASE("ulp controls RTC_IO", "[ulp]") +TEST_CASE("ulp controls RTC_IO", "[ulp][ignore]") { assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig"); memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM); diff --git a/components/vfs/README.rst b/components/vfs/README.rst index 2ad7aa7ec2..26d857fc8d 100644 --- a/components/vfs/README.rst +++ b/components/vfs/README.rst @@ -140,7 +140,7 @@ actually is translated to to this (by the preprocessor): fprintf(__getreent()->_stderr, "42\n"); -where the ``__getreent()`` function returns a per-task pointer to ``struct _reent`` (`source `_). This structure is allocated on the TCB of each task. When a task is initialized, ``_stdin``, ``_stdout`` and ``_stderr`` members of ``struct _reent`` are set to the values of ``_stdin``, ``_stdout`` and ``_stderr`` of ``_GLOBAL_REENT`` (i.e. the structure which is used before FreeRTOS is started). +where the ``__getreent()`` function returns a per-task pointer to ``struct _reent`` (:component_file:`newlib/include/sys/reent.h#L370-L417>`). This structure is allocated on the TCB of each task. When a task is initialized, ``_stdin``, ``_stdout`` and ``_stderr`` members of ``struct _reent`` are set to the values of ``_stdin``, ``_stdout`` and ``_stderr`` of ``_GLOBAL_REENT`` (i.e. the structure which is used before FreeRTOS is started). Such a design has the following consequences: diff --git a/docs/COPYRIGHT.rst b/docs/COPYRIGHT.rst index 67b3d9bf1c..0e0d457207 100644 --- a/docs/COPYRIGHT.rst +++ b/docs/COPYRIGHT.rst @@ -14,7 +14,7 @@ Additional third party copyrighted code is included under the following licenses * Xtensa header files (components/esp32/include/xtensa) are Copyright (C) 2013 Tensilica Inc and are licensed under the MIT License as reproduce in the individual header files. -* `esptool.py`_ (bin/esptool.py) is Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton and is licensed under the GNU General Public License v2, as described in the file components/esptool_py/LICENSE. +* `esptool.py`_ (components/esptool_py/esptool) is Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton and is licensed under the GNU General Public License v2, as described in the file components/esptool_py/LICENSE. * Original parts of FreeRTOS_ (components/freertos) are Copyright (C) 2015 Real Time Engineers Ltd and is licensed under the GNU General Public License V2 with the FreeRTOS Linking Exception, as described in the file components/freertos/license.txt. @@ -96,7 +96,7 @@ Copyright (C) 2011, ChaN, all right reserved. .. _Newlib: https://sourceware.org/newlib/ .. _FreeRTOS: http://freertos.org/ -.. _esptool.py: https://github.com/themadinventor/esptool +.. _esptool.py: https://github.com/espressif/esptool .. _LWIP: http://savannah.nongnu.org/projects/lwip/ .. _TinyBasic: https://github.com/BleuLlama/TinyBasicPlus .. _miniz: https://code.google.com/archive/p/miniz/ diff --git a/docs/Doxyfile b/docs/Doxyfile index aa6c87476e..43d2273819 100755 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -37,7 +37,8 @@ INPUT = ../components/esp32/include/esp_wifi.h \ ../components/fatfs/src/esp_vfs_fat.h \ ../components/fatfs/src/diskio.h \ ../components/esp32/include/esp_core_dump.h \ - ../components/mdns/include/mdns.h + ../components/mdns/include/mdns.h \ + ../components/bootloader_support/include/esp_flash_encrypt.h ## Get warnings for functions that have no documentation for their parameters or return value ## diff --git a/docs/Makefile b/docs/Makefile index c04268ff1d..8076416b78 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -161,6 +161,30 @@ linkcheck: @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." +gh-linkcheck: + @echo "Checking for hardcoded GitHub links" + @if (find ../ -name '*.rst' | xargs grep \ + 'https://github.com/espressif/esp-idf/tree\|https://github.com/espressif/esp-idf/blob\|https://github.com/espressif/esp-idf/raw'\ + ); \ + then \ + echo "WARNINIG: Some .rst files contain hardcoded Github links."; \ + echo "Please check above output and replace links with one of the following:"; \ + echo "- :idf:\`dir\` - points to directory inside ESP-IDF"; \ + echo "- :idf_blob:\`file\` - points to file inside ESP-IDF"; \ + echo "- :idf_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \ + echo "- :component:\`dir\` - points to directory inside ESP-IDF components dir"; \ + echo "- :component_blob:\`file\` - points to file inside ESP-IDF components dir"; \ + echo "- :component_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \ + echo " components dir"; \ + echo "- :example:\`dir\` - points to directory inside ESP-IDF examples dir"; \ + echo "- :example_blob:\`file\` - points to file inside ESP-IDF examples dir"; \ + echo "- :example_raw:\`file\` - points to raw view of the file inside ESP-IDF"; \ + echo " examples dir"; \ + echo "These link types will point to the correct GitHub version automatically"; \ + exit 1; \ + fi + @echo "No hardcoded links found" + doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..475ce0973e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,11 @@ +# Documentation Source Folder + +This folder contains source files of [ESP-IDF documentation](http://esp-idf.readthedocs.io/). + +The sources do not render well in GitHub and some information is not visible at all. + +Use actual documentation generated instantly on each commit: + +* Main server: http://esp-idf.readthedocs.io/ or http://esp-idf.rtfd.io/ +* Mirror: https://dl.espressif.com/doc/esp-idf/latest/ + diff --git a/docs/api/bt_common.rst b/docs/api/bluetooth/bt_common.rst similarity index 100% rename from docs/api/bt_common.rst rename to docs/api/bluetooth/bt_common.rst diff --git a/docs/api/bt_le.rst b/docs/api/bluetooth/bt_le.rst similarity index 100% rename from docs/api/bt_le.rst rename to docs/api/bluetooth/bt_le.rst diff --git a/docs/api/controller_vhci.rst b/docs/api/bluetooth/controller_vhci.rst similarity index 61% rename from docs/api/controller_vhci.rst rename to docs/api/bluetooth/controller_vhci.rst index a9c1a79289..9fc5910c25 100644 --- a/docs/api/controller_vhci.rst +++ b/docs/api/bluetooth/controller_vhci.rst @@ -6,26 +6,24 @@ Overview `Instructions`_ +.. _Instructions: ../template.html + Application Example ------------------- -Check `/examples `_ folder of `espressif/esp-idf `_ repository, that contains the following example: +Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following example: -`05_ble_adv `_ +:example:`bluetooth/ble_adv` This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising. -`Instructions`_ - -.. _Instructions: template.html - API Reference ------------- Header Files ^^^^^^^^^^^^ - * `bt/include/bt.h `_ + * :component_file:`bt/include/bt.h` Type Definitions ^^^^^^^^^^^^^^^^ @@ -35,6 +33,7 @@ Type Definitions Enumerations ^^^^^^^^^^^^ +.. doxygenenum:: esp_bt_mode_t Structures ^^^^^^^^^^ @@ -47,6 +46,10 @@ Functions ^^^^^^^^^ .. doxygenfunction:: esp_bt_controller_init +.. doxygenfunction:: esp_bt_controller_deinit +.. doxygenfunction:: esp_bt_controller_enable +.. doxygenfunction:: esp_bt_controller_disable +.. doxygenfunction:: esp_bt_controller_get_status .. doxygenfunction:: esp_vhci_host_check_send_available .. doxygenfunction:: esp_vhci_host_send_packet .. doxygenfunction:: esp_vhci_host_register_callback diff --git a/docs/api/esp_blufi.rst b/docs/api/bluetooth/esp_blufi.rst similarity index 84% rename from docs/api/esp_blufi.rst rename to docs/api/bluetooth/esp_blufi.rst index 13432dc154..5a1b1595a9 100644 --- a/docs/api/esp_blufi.rst +++ b/docs/api/bluetooth/esp_blufi.rst @@ -11,11 +11,11 @@ Use should concern these things: Application Example ------------------- -Check `/examples `_ folder of `espressif/esp-idf `_ repository, that contains the following example: +Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following example: -`12_blufi `_ +:example:`bluetooth/blufi` -This is a BLUFI demo. This demo can set ESP32's wifi to softap/station/softap&station mode and config wifi connections. + This is a BLUFI demo. This demo can set ESP32's wifi to softap/station/softap&station mode and config wifi connections. API Reference @@ -24,7 +24,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `bt/bluedroid/api/include/esp_blufi_api.h `_ + * :component_file:`bt/bluedroid/api/include/esp_blufi_api.h` Macros ^^^^^^ diff --git a/docs/api/esp_bt_defs.rst b/docs/api/bluetooth/esp_bt_defs.rst similarity index 82% rename from docs/api/esp_bt_defs.rst rename to docs/api/bluetooth/esp_bt_defs.rst index 801b13df78..527fe9359f 100644 --- a/docs/api/esp_bt_defs.rst +++ b/docs/api/bluetooth/esp_bt_defs.rst @@ -11,7 +11,7 @@ Application Example `Instructions`_ -.. _Instructions: template.html +.. _Instructions: ../template.html API Reference @@ -20,7 +20,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `bt/bluedroid/api/include/esp_bt_defs.h `_ + * :component_file:`bt/bluedroid/api/include/esp_bt_defs.h` Macros diff --git a/docs/api/esp_bt_device.rst b/docs/api/bluetooth/esp_bt_device.rst similarity index 68% rename from docs/api/esp_bt_device.rst rename to docs/api/bluetooth/esp_bt_device.rst index c344a5e633..50e9dcf1a0 100644 --- a/docs/api/esp_bt_device.rst +++ b/docs/api/bluetooth/esp_bt_device.rst @@ -13,7 +13,7 @@ Application Example `Instructions`_ -.. _Instructions: template.html +.. _Instructions: ../template.html API Reference @@ -22,7 +22,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `bt/bluedroid/api/include/esp_bt_device.h `_ + * :component_file:`bt/bluedroid/api/include/esp_bt_device.h` Macros diff --git a/docs/api/esp_bt_main.rst b/docs/api/bluetooth/esp_bt_main.rst similarity index 75% rename from docs/api/esp_bt_main.rst rename to docs/api/bluetooth/esp_bt_main.rst index 48bb0c9cc0..1c085a1347 100644 --- a/docs/api/esp_bt_main.rst +++ b/docs/api/bluetooth/esp_bt_main.rst @@ -11,7 +11,7 @@ Application Example `Instructions`_ -.. _Instructions: template.html +.. _Instructions: ../template.html API Reference @@ -20,7 +20,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `bt/bluedroid/api/include/esp_bt_main.h `_ + * :component_file:`bt/bluedroid/api/include/esp_bt_main.h` Macros diff --git a/docs/api/esp_gap_ble.rst b/docs/api/bluetooth/esp_gap_ble.rst similarity index 76% rename from docs/api/esp_gap_ble.rst rename to docs/api/bluetooth/esp_gap_ble.rst index 856ed27302..fea9376304 100644 --- a/docs/api/esp_gap_ble.rst +++ b/docs/api/bluetooth/esp_gap_ble.rst @@ -1,25 +1,21 @@ GAP API -======== +======= Overview -------- `Instructions`_ +.. _Instructions: ../template.html + Application Example ------------------- -Check `/examples `_ folder of `espressif/esp-idf `_ repository, that contains the following example: +Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following examples: -`14_gatts_demo `_ -`15_gattc_demo `_ - -The two demos use different gap api, such like advertising, scan, set device name and others. - -`Instructions`_ - -.. _Instructions: template.html +:example:`bluetooth/gatt_server`, :example:`bluetooth/gatt_client` + The two demos use different GAP APIs, such like advertising, scan, set device name and others. API Reference ------------- @@ -27,7 +23,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `bt/bluedroid/api/include/esp_gap_ble_api.h `_ + * :component_file:`bt/bluedroid/api/include/esp_gap_ble_api.h` Macros @@ -40,6 +36,7 @@ Macros .. doxygendefine:: ESP_BLE_ADV_FLAG_DMT_HOST_SPT .. doxygendefine:: ESP_BLE_ADV_FLAG_NON_LIMIT_DISC .. doxygendefine:: ESP_BLE_ADV_DATA_LEN_MAX +.. doxygendefine:: ESP_BLE_SCAN_RSP_DATA_LEN_MAX Type Definitions ^^^^^^^^^^^^^^^^ @@ -90,6 +87,12 @@ Structures .. doxygenstruct:: esp_ble_gap_cb_param_t::ble_scan_result_evt_param :members: +.. doxygenstruct:: esp_ble_gap_cb_param_t::ble_adv_data_raw_cmpl_evt_param + :members: + +.. doxygenstruct:: esp_ble_gap_cb_param_t::ble_scan_rsp_data_raw_cmpl_evt_param + :members: + Functions ^^^^^^^^^ @@ -107,4 +110,6 @@ Functions .. doxygenfunction:: esp_ble_gap_config_local_privacy .. doxygenfunction:: esp_ble_gap_set_device_name .. doxygenfunction:: esp_ble_resolve_adv_data +.. doxygenfunction:: esp_ble_gap_config_adv_data_raw +.. doxygenfunction:: esp_ble_gap_config_scan_rsp_data_raw diff --git a/docs/api/esp_gatt_defs.rst b/docs/api/bluetooth/esp_gatt_defs.rst similarity index 96% rename from docs/api/esp_gatt_defs.rst rename to docs/api/bluetooth/esp_gatt_defs.rst index 70e808a5d7..11cb640279 100644 --- a/docs/api/esp_gatt_defs.rst +++ b/docs/api/bluetooth/esp_gatt_defs.rst @@ -11,7 +11,7 @@ Application Example `Instructions`_ -.. _Instructions: template.html +.. _Instructions: ../template.html API Reference @@ -20,7 +20,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `bt/bluedroid/api/include/esp_gatt_defs.h `_ + * :component_file:`bt/bluedroid/api/include/esp_gatt_defs.h` Macros diff --git a/docs/api/esp_gattc.rst b/docs/api/bluetooth/esp_gattc.rst similarity index 82% rename from docs/api/esp_gattc.rst rename to docs/api/bluetooth/esp_gattc.rst index 7ff1e9de7e..b41c7e09e3 100644 --- a/docs/api/esp_gattc.rst +++ b/docs/api/bluetooth/esp_gattc.rst @@ -6,18 +6,16 @@ Overview `Instructions`_ +.. _Instructions: ../template.html + Application Example ------------------- -Check `/examples `_ folder of `espressif/esp-idf `_ repository, that contains the following example: +Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following examples: -`15_gattc_demo `_ +:example:`bluetooth/gatt_client` -This is a gatt client demo. This demo can scan devices, connect to the gatt server and discover the service. - -`Instructions`_ - -.. _Instructions: template.html + This is a GATT client demo. This demo can scan devices, connect to the GATT server and discover the service. API Reference @@ -26,7 +24,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `bt/bluedroid/api/include/esp_gattc_api.h `_ + * :component_file:`bt/bluedroid/api/include/esp_gattc_api.h` Macros ^^^^^^ diff --git a/docs/api/esp_gatts.rst b/docs/api/bluetooth/esp_gatts.rst similarity index 81% rename from docs/api/esp_gatts.rst rename to docs/api/bluetooth/esp_gatts.rst index 4278e6b33e..8f0414d67f 100644 --- a/docs/api/esp_gatts.rst +++ b/docs/api/bluetooth/esp_gatts.rst @@ -6,19 +6,16 @@ Overview `Instructions`_ +.. _Instructions: ../template.html + Application Example ------------------- -Check `/examples `_ folder of `espressif/esp-idf `_ repository, that contains the following example: +Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following example: -`14_gatts_demo `_ - -This is a gatt server demo. Use gatt api to create a gatt server with send advertising. This gatt server can be connected and the service can be discovery. - -`Instructions`_ - -.. _Instructions: template.html +:example:`bluetooth/gatt_server` + This is a GATT server demo. Use GATT API to create a GATT server with send advertising. This GATT server can be connected and the service can be discovery. API Reference ------------- @@ -26,7 +23,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `bt/bluedroid/api/include/esp_gatts_api.h `_ + * :component_file:`bt/bluedroid/api/include/esp_gatts_api.h` Macros ^^^^^^ diff --git a/docs/api/bluetooth/index.rst b/docs/api/bluetooth/index.rst new file mode 100644 index 0000000000..996a26e138 --- /dev/null +++ b/docs/api/bluetooth/index.rst @@ -0,0 +1,12 @@ +Bluetooth API +************* + +.. toctree:: + :maxdepth: 2 + + Bluetooth Controller && VHCI + Bluetooth Common + Bluetooth LE + + +Example code for this API section is provided in :example:`bluetooth` directory of ESP-IDF examples. diff --git a/docs/api/bt.rst b/docs/api/bt.rst deleted file mode 100644 index 2eae5dd4cf..0000000000 --- a/docs/api/bt.rst +++ /dev/null @@ -1,9 +0,0 @@ -Bluetooth -========= - -.. toctree:: - :caption: Bluetooth APIs - - Bluetooth Controller && VHCI - Bluetooth Common - Bluetooth LE diff --git a/docs/api/esp_eth.rst b/docs/api/ethernet/esp_eth.rst similarity index 81% rename from docs/api/esp_eth.rst rename to docs/api/ethernet/esp_eth.rst index 371aa5b233..fbecdca339 100644 --- a/docs/api/esp_eth.rst +++ b/docs/api/ethernet/esp_eth.rst @@ -4,7 +4,7 @@ ETHERNET Application Example ------------------- -ethernet example: `examples/17_ethernet `_. +Ethernet example: :example:`ethernet/ethernet`. API Reference ------------- @@ -12,7 +12,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `components/ethernet/include/esp_eth.h `_ + * :component_file:`ethernet/include/esp_eth.h` Macros ^^^^^^ diff --git a/docs/api/ethernet/index.rst b/docs/api/ethernet/index.rst new file mode 100644 index 0000000000..6e95831d32 --- /dev/null +++ b/docs/api/ethernet/index.rst @@ -0,0 +1,10 @@ +Ethernet API +************ + +.. toctree:: + :maxdepth: 1 + + Ethernet + + +Example code for this API section is provided in :example:`ethernet` directory of ESP-IDF examples. diff --git a/docs/api/peripherals/adc.rst b/docs/api/peripherals/adc.rst new file mode 100644 index 0000000000..8d598f327f --- /dev/null +++ b/docs/api/peripherals/adc.rst @@ -0,0 +1,62 @@ +Analog to Digital Converter +=========================== + +Overview +-------- + +ESP32 integrates two 12-bit SAR ("Successive Approximation Register") ADCs (Analog to Digital Converters) and supports measurements on 18 channels (analog enabled pins). Some of these pins can be used to build a programmable gain amplifier which is used for the measurement of small +analog signals. + +The ADC driver API currently only supports ADC1 (9 channels, attached to GPIOs 32-39). + +Taking an ADC reading involves configuring the ADC with the desired precision and attentuation settings, and then calling adc1_get_voltage() to read the channel. + +It is also possible to read the internal hall effect sensor via ADC1. + +Application Example +------------------- + +Reading voltage on ADC1 channel 0 (GPIO 36):: + + #include + + ... + + adc1_config_width(ADC_WIDTH_12Bit); + adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_0db); + int val = adc1_get_voltage(ADC1_CHANNEL_0); + +Reading the internal hall effect sensor:: + + #include + + ... + + adc1_config_width(ADC_WIDTH_12Bit); + int val = hall_sensor_read(); + +The value read in both these examples is 12 bits wide (range 0-4095). + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * `components/driver/include/driver/adc.h` + +Enumerations +^^^^^^^^^^^^ + + .. doxygenenum:: adc1_channel_t + .. doxygenenum:: adc_atten_t + .. doxygenenum:: adc_bits_width_t + +Functions +^^^^^^^^^ + + .. doxygenfunction:: adc1_config_width + .. doxygenfunction:: adc1_config_channel_atten + .. doxygenfunction:: adc1_get_voltage + .. doxygenfunction:: hall_sensor_read + diff --git a/docs/api/peripherals/dac.rst b/docs/api/peripherals/dac.rst new file mode 100644 index 0000000000..ec17c31cac --- /dev/null +++ b/docs/api/peripherals/dac.rst @@ -0,0 +1,45 @@ +Digital To Analog Converter +=========================== + +Overview +-------- + +ESP32 has two 8-bit DAC (digital to analog converter) channels, connected to GPIO25 (Channel 1) and GPIO26 (Channel 2). + +The DAC driver allows these channels to be set to arbitrary voltages. + +The DAC channels can also be driven with DMA-style written sample data, via the :doc:`I2S driver ` when using the "built-in DAC mode". + +For other analog output options, see the :doc:`Sigma-delta Modulation module ` and the :doc:`LED Control module `. Both these modules produce high frequency PWM output, which can be hardware low-pass filtered in order to generate a lower frequency analog output. + + +Application Example +------------------- + +Setting DAC channel 1 (GPIO 25) voltage to approx 0.78 of VDD_A voltage (VDD * 200 / 255). For VDD_A 3.3V, this is 2.59V:: + + #include + + ... + + dac_out_voltage(DAC_CHANNEL_1, 200); + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * `components/driver/include/driver/dac.h` + +Enumerations +^^^^^^^^^^^^ + + .. doxygenenum:: dac_channel_t + +Functions +^^^^^^^^^ + + .. doxygenfunction:: dac_out_voltage + + diff --git a/docs/api/gpio.rst b/docs/api/peripherals/gpio.rst similarity index 76% rename from docs/api/gpio.rst rename to docs/api/peripherals/gpio.rst index f331b9d265..a4f2ea81d3 100644 --- a/docs/api/gpio.rst +++ b/docs/api/peripherals/gpio.rst @@ -1,16 +1,20 @@ -GPIO -==== +GPIO & RTC GPIO +=============== Overview -------- The ESP32 chip features 40 physical GPIO pads. Some GPIO pads cannot be used or do not have the corresponding pin on the chip package(refer to technical reference manual ). Each pad can be used as a general purpose I/O or can be connected to an internal peripheral signal. -Note that GPIO6-11 are usually used for SPI flash. GPIO34-39 can only be set as input mode. + +- Note that GPIO6-11 are usually used for SPI flash. +- GPIO34-39 can only be set as input mode and do not have software pullup or pulldown functions. + +There is also separate "RTC GPIO" support, which functions when GPIOs are routed to the "RTC" low-power and analog subsystem. These pin functions can be used when in deep sleep, when the :doc:`Ultra Low Power co-processor ` is running, or when analog functions such as ADC/DAC/etc are in use. Application Example ------------------- -GPIO output and input interrupt example: `examples/21_gpio `_. +GPIO output and input interrupt example: :example:`peripherals/gpio`. API Reference ------------- @@ -18,11 +22,15 @@ API Reference Header Files ^^^^^^^^^^^^ - * `driver/include/driver/driver/gpio.h `_ + * :component_file:`driver/include/driver/gpio.h` + * :component_file:`driver/include/driver/rtc_io.h` Macros ^^^^^^ +Normal GPIO +~~~~~~~~~~~ + .. doxygendefine:: GPIO_SEL_0 .. doxygendefine:: GPIO_SEL_1 .. doxygendefine:: GPIO_SEL_2 @@ -107,12 +115,18 @@ Macros Type Definitions ^^^^^^^^^^^^^^^^ +Normal GPIO +~~~~~~~~~~~ + .. doxygentypedef:: gpio_isr_t .. doxygentypedef:: gpio_isr_handle_t Enumerations ^^^^^^^^^^^^ +Normal GPIO +~~~~~~~~~~~ + .. doxygenenum:: gpio_num_t .. doxygenenum:: gpio_int_type_t .. doxygenenum:: gpio_mode_t @@ -120,16 +134,26 @@ Enumerations .. doxygenenum:: gpio_pulldown_t .. doxygenenum:: gpio_pull_mode_t +RTC GPIO +~~~~~~~~ + +.. doxygenenum:: rtc_gpio_mode_t + Structures ^^^^^^^^^^ +Normal GPIO +~~~~~~~~~~~ + .. doxygenstruct:: gpio_config_t :members: - Functions ^^^^^^^^^ +Normal GPIO +~~~~~~~~~~~ + .. doxygenfunction:: gpio_config .. doxygenfunction:: gpio_set_intr_type .. doxygenfunction:: gpio_intr_enable @@ -150,3 +174,18 @@ Functions .. doxygenfunction:: gpio_isr_handler_add .. doxygenfunction:: gpio_isr_handler_remove + +RTC GPIO +~~~~~~~~ + +.. doxygenfunction:: rtc_gpio_is_valid_gpio +.. doxygenfunction:: rtc_gpio_init +.. doxygenfunction:: rtc_gpio_deinit +.. doxygenfunction:: rtc_gpio_get_level +.. doxygenfunction:: rtc_gpio_set_level +.. doxygenfunction:: rtc_gpio_set_direction +.. doxygenfunction:: rtc_gpio_pullup_en +.. doxygenfunction:: rtc_gpio_pulldown_en +.. doxygenfunction:: rtc_gpio_pullup_dis +.. doxygenfunction:: rtc_gpio_pulldown_dis +.. doxygenfunction:: rtc_gpio_unhold_all diff --git a/docs/api/i2c.rst b/docs/api/peripherals/i2c.rst similarity index 88% rename from docs/api/i2c.rst rename to docs/api/peripherals/i2c.rst index 2f89681f1d..bd30a345d8 100644 --- a/docs/api/i2c.rst +++ b/docs/api/peripherals/i2c.rst @@ -9,7 +9,7 @@ ESP32 has two I2C controllers which can be set as master mode or slave mode. Application Example ------------------- -I2C master and slave example: `examples/18_i2c `_. +I2C master and slave example: :example:`peripherals/i2c`. API Reference ------------- @@ -17,7 +17,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `driver/include/driver/i2c.h `_ + * :component_file:`driver/include/driver/i2c.h` Macros ^^^^^^ diff --git a/docs/api/peripherals/i2s.rst b/docs/api/peripherals/i2s.rst new file mode 100644 index 0000000000..57ce422a8a --- /dev/null +++ b/docs/api/peripherals/i2s.rst @@ -0,0 +1,131 @@ +I2S +=== + +Overview +-------- + +ESP32 contains two I2S peripherals. These peripherals can be configured to input and output sample data via the I2S driver. + +The I2S peripheral supports DMA meaning it can stream sample data without requiring each sample to be read or written by the CPU. + +I2S output can also be routed directly to the Digital/Analog Converter output channels (GPIO 25 & GPIO 26) to produce analog output directly, rather than via an external I2S codec. + +Application Example +------------------- + +A full I2S example is available in esp-idf: :example:`peripherals/i2s`. + +Short example of I2S configuration:: + + #include "driver/i2s.h" + #include "freertos/queue.h" + + static const int i2s_num = 0; // i2s port number + + static const i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = 44100, + .bits_per_sample = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 64 + }; + + static const i2s_pin_config_t pin_config = { + .bck_io_num = 26, + .ws_io_num = 25, + .data_out_num = 22, + .data_in_num = I2S_PIN_NO_CHANGE + }; + + ... + + i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver + + i2s_set_pin(i2s_num, &pin_config); + + i2s_set_sample_rates(i2s_num, 22050); //set sample rates + + i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver + +Short example configuring I2S to use internal DAC for analog output:: + + #include "driver/i2s.h" + #include "freertos/queue.h" + + static const int i2s_num = 0; // i2s port number + + static const i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, + .sample_rate = 44100, + .bits_per_sample = 8, /* must be 8 for built-in DAC */ + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_I2S_MSB, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 64 + }; + + ... + + i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver + + i2s_set_pin(i2s_num, NULL); //for internal DAC + + i2s_set_sample_rates(i2s_num, 22050); //set sample rates + + i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * `components/driver/include/driver/i2s.h` + +Data Structures +^^^^^^^^^^^^^^^ + + .. doxygenstruct:: i2s_config_t + :members: + .. doxygenstruct:: i2s_event_t + :members: + .. doxygenstruct:: i2s_pin_config_t + :members: + +Macros +^^^^^^ + + .. doxygendefine:: I2S_PIN_NO_CHANGE + +Enumerations +^^^^^^^^^^^^ + + .. doxygenenum:: i2s_bits_per_sample_t + .. doxygenenum:: i2s_comm_format_t + .. doxygenenum:: i2s_channel_fmt_t + .. doxygenenum:: pdm_sample_rate_ratio_t + .. doxygenenum:: pdm_pcm_conv_t + .. doxygenenum:: i2s_port_t + .. doxygenenum:: i2s_mode_t + .. doxygenenum:: i2s_event_type_t + +Functions +^^^^^^^^^ + + .. doxygenfunction:: i2s_set_pin + .. doxygenfunction:: i2s_driver_install + .. doxygenfunction:: i2s_driver_uninstall + .. doxygenfunction:: i2s_write_bytes + .. doxygenfunction:: i2s_read_bytes + .. doxygenfunction:: i2s_push_sample + .. doxygenfunction:: i2s_pop_sample + .. doxygenfunction:: i2s_set_sample_rates + .. doxygenfunction:: i2s_start + .. doxygenfunction:: i2s_stop + .. doxygenfunction:: i2s_zero_dma_buffer + + diff --git a/docs/api/peripherals/index.rst b/docs/api/peripherals/index.rst new file mode 100644 index 0000000000..167c7b9952 --- /dev/null +++ b/docs/api/peripherals/index.rst @@ -0,0 +1,21 @@ +Peripherals API +*************** + +.. toctree:: + :maxdepth: 1 + + ADC + DAC + GPIO (including RTC low power I/O) + I2C + I2S + LED Control + Pulse Counter + SD/MMC Card Host <../storage/sdmmc> + Sigma-delta Modulation + SPI Master + Remote Control + Timer + UART + +Example code for this API section is provided in :example:`peripherals` directory of ESP-IDF examples. diff --git a/docs/api/ledc.rst b/docs/api/peripherals/ledc.rst similarity index 88% rename from docs/api/ledc.rst rename to docs/api/peripherals/ledc.rst index 12d7cd16d0..a1a96543dc 100644 --- a/docs/api/ledc.rst +++ b/docs/api/peripherals/ledc.rst @@ -12,7 +12,7 @@ decrease the duty cycle gradually, allowing for fades without any processor inte Application Example ------------------- -LEDC change duty cycle and fading control example: `examples/29_ledc `_. +LEDC change duty cycle and fading control example: :example:`peripherals/ledc`. API Reference ------------- @@ -20,7 +20,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `driver/include/driver/ledc.h `_ + * :component_file:`driver/include/driver/ledc.h` Macros ^^^^^^ diff --git a/docs/api/pcnt.rst b/docs/api/peripherals/pcnt.rst similarity index 86% rename from docs/api/pcnt.rst rename to docs/api/peripherals/pcnt.rst index 7fe73e6f47..63e6ad6443 100644 --- a/docs/api/pcnt.rst +++ b/docs/api/peripherals/pcnt.rst @@ -9,7 +9,7 @@ The PCNT (Pulse Counter) module is designed to count the number of rising and/or Application Example ------------------- -Pulse counter with control signal and event interrupt example: `examples/16_pcnt `_. +Pulse counter with control signal and event interrupt example: :example:`peripherals/pcnt`. API Reference ------------- @@ -17,7 +17,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `driver/pcnt.h `_ + * :component_file:`driver/include/driver/pcnt.h` Macros diff --git a/docs/api/rmt.rst b/docs/api/peripherals/rmt.rst similarity index 90% rename from docs/api/rmt.rst rename to docs/api/peripherals/rmt.rst index 9d834b1e28..276ed939e1 100644 --- a/docs/api/rmt.rst +++ b/docs/api/peripherals/rmt.rst @@ -9,7 +9,7 @@ The RMT (Remote Control) module driver can be used to send and receive infrared Application Example ------------------- -NEC remote control TX and RX example: `examples/11_rmt_nec_tx_rx `_. +NEC remote control TX and RX example: :example:`peripherals/rmt_nec_tx_rx`. API Reference ------------- @@ -17,7 +17,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `driver/rmt.h `_ + * :component_file:`driver/include/driver/rmt.h` Macros ^^^^^^ diff --git a/docs/api/sigmadelta.rst b/docs/api/peripherals/sigmadelta.rst similarity index 66% rename from docs/api/sigmadelta.rst rename to docs/api/peripherals/sigmadelta.rst index b03f049421..d2e423deb1 100644 --- a/docs/api/sigmadelta.rst +++ b/docs/api/peripherals/sigmadelta.rst @@ -4,13 +4,13 @@ Sigma-delta Modulation Overview -------- -ESP32 has a second-order sigma-delta modulation module. +ESP32 has a second-order sigma-delta modulation module. This driver configures the channels of the sigma-delta module. Application Example ------------------- -Sigma-delta Modulation example: `examples/14_sigmadelta `_. +Sigma-delta Modulation example: :example:`peripherals/sigmadelta`. API Reference ------------- @@ -18,7 +18,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `driver/sigmadelta.h `_ + * :component_file:`driver/include/driver/sigmadelta.h` Macros diff --git a/docs/api/spi_master.rst b/docs/api/peripherals/spi_master.rst similarity index 97% rename from docs/api/spi_master.rst rename to docs/api/peripherals/spi_master.rst index 5b57d85f42..78039cbd79 100644 --- a/docs/api/spi_master.rst +++ b/docs/api/peripherals/spi_master.rst @@ -105,13 +105,18 @@ on the transmission. For received data, use ``rx_data`` and set ``SPI_USE_RXDATA not touch the ``tx_buffer`` or ``rx_buffer`` members, because they use the same memory locations as ``tx_data`` and ``rx_data``. +Application Example +------------------- + +Display graphics on the ILI9341-based 320x240 LCD: :example:`peripherals/spi_master`. + API Reference ------------- Header Files ^^^^^^^^^^^^ - * `drivers/include/drivers/spi_master.h `_ + * :component_file:`driver/include/driver/spi_master.h` Macros ^^^^^^ diff --git a/docs/api/timer.rst b/docs/api/peripherals/timer.rst similarity index 85% rename from docs/api/timer.rst rename to docs/api/peripherals/timer.rst index 0db0a12c23..7b5253fde1 100644 --- a/docs/api/timer.rst +++ b/docs/api/peripherals/timer.rst @@ -12,7 +12,7 @@ They are all 64-bit generic timers based on 16-bit prescalers and 64-bit auto-re Application Example ------------------- -64-bit hardware timer example: `examples/13_timer_group `_. +64-bit hardware timer example: :example:`peripherals/timer_group`. API Reference ------------- @@ -20,7 +20,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `components/driver/timer.h `_ + * :component_file:`driver/include/driver/timer.h` Macros ^^^^^^ diff --git a/docs/api/uart.rst b/docs/api/peripherals/uart.rst similarity index 91% rename from docs/api/uart.rst rename to docs/api/peripherals/uart.rst index fa83309e2a..1392361d9f 100644 --- a/docs/api/uart.rst +++ b/docs/api/peripherals/uart.rst @@ -6,22 +6,20 @@ Overview `Instructions`_ +.. _Instructions: ../template.html + Application Example ------------------- -`Instructions`_ +Configure uart settings and install uart driver to read/write using UART0 and UART1 interfaces: :example:`peripherals/uart`. API Reference ------------- -`Instructions`_ - -.. _Instructions: template.html - Header Files ^^^^^^^^^^^^ - * `driver/include/driver/uart.h `_ + * :component_file:`driver/include/driver/uart.h` Data Structures ^^^^^^^^^^^^^^^ diff --git a/docs/api/protocols/index.rst b/docs/api/protocols/index.rst new file mode 100644 index 0000000000..b5572d8cd6 --- /dev/null +++ b/docs/api/protocols/index.rst @@ -0,0 +1,10 @@ +Protocols API +************* + +.. toctree:: + :maxdepth: 1 + + mDNS + + +Example code for this API section is provided in :example:`protocols` directory of ESP-IDF examples. diff --git a/docs/api/mdns.rst b/docs/api/protocols/mdns.rst similarity index 96% rename from docs/api/mdns.rst rename to docs/api/protocols/mdns.rst index 95789444f5..1355642de1 100644 --- a/docs/api/mdns.rst +++ b/docs/api/protocols/mdns.rst @@ -163,7 +163,7 @@ Example of using the methods above: Application Example ------------------- -mDNS server/scanner example: `examples/30_mdns_example `_. +mDNS server/scanner example: :example:`protocols/mdns`. API Reference ------------- @@ -171,7 +171,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `components/mdns/include/mdns.h `_ + * :component_file:`mdns/include/mdns.h` Macros ^^^^^^ diff --git a/docs/api/fatfs.rst b/docs/api/storage/fatfs.rst similarity index 100% rename from docs/api/fatfs.rst rename to docs/api/storage/fatfs.rst diff --git a/docs/api/storage/index.rst b/docs/api/storage/index.rst new file mode 100644 index 0000000000..207ad01ccb --- /dev/null +++ b/docs/api/storage/index.rst @@ -0,0 +1,14 @@ +Storage API +*********** + +.. toctree:: + :maxdepth: 1 + + SPI Flash and Partition APIs + SD/MMC + Non-Volatile Storage + Virtual Filesystem + FAT Filesystem + + +Example code for this API section is provided in :example:`storage` directory of ESP-IDF examples. diff --git a/docs/api/nvs_flash.rst b/docs/api/storage/nvs_flash.rst similarity index 82% rename from docs/api/nvs_flash.rst rename to docs/api/storage/nvs_flash.rst index e2ac34ada8..ce1af94546 100644 --- a/docs/api/nvs_flash.rst +++ b/docs/api/storage/nvs_flash.rst @@ -1,11 +1,11 @@ -.. include:: ../../components/nvs_flash/README.rst +.. include:: ../../../components/nvs_flash/README.rst Application Example ------------------- -Two examples are provided in ESP-IDF examples directory: +Two examples are provided in :example:`storage` directory of ESP-IDF examples: -`07_nvs_rw_value `_ +:example:`storage/nvs_rw_value` Demonstrates how to read and write a single integer value using NVS. @@ -13,7 +13,7 @@ Two examples are provided in ESP-IDF examples directory: Example also shows how to check if read / write operation was successful, or certain value is not initialized in NVS. Diagnostic is provided in plain text to help track program flow and capture any issues on the way. -`08_nvs_rw_blob `_ +:example:`storage/nvs_rw_blob` Demonstrates how to read and write a single integer value and a blob (binary large object) using NVS to preserve them between ESP32 module restarts. @@ -29,8 +29,8 @@ API Reference Header Files ^^^^^^^^^^^^ - * `nvs_flash/include/nvs_flash.h `_ - * `nvs_flash/include/nvs.h `_ + * :component_file:`nvs_flash/include/nvs_flash.h` + * :component_file:`nvs_flash/include/nvs.h` Macros ^^^^^^ diff --git a/docs/api/sdmmc.rst b/docs/api/storage/sdmmc.rst similarity index 95% rename from docs/api/sdmmc.rst rename to docs/api/storage/sdmmc.rst index e751852f95..fe2e5c27f8 100644 --- a/docs/api/sdmmc.rst +++ b/docs/api/storage/sdmmc.rst @@ -15,7 +15,7 @@ Protocol layer works with the host via ``sdmmc_host_t`` structure. This structur Application Example ------------------- -An example which combines SDMMC driver with FATFS library is provided in ``examples/27_sd_card`` directory. This example initializes the card, writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information. +An example which combines SDMMC driver with FATFS library is provided in ``examples/storage/sd_card`` directory. This example initializes the card, writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information. Protocol layer APIs diff --git a/docs/api/spi_flash.rst b/docs/api/storage/spi_flash.rst similarity index 76% rename from docs/api/spi_flash.rst rename to docs/api/storage/spi_flash.rst index 5903c0902d..5725ceb0c9 100644 --- a/docs/api/spi_flash.rst +++ b/docs/api/storage/spi_flash.rst @@ -1,11 +1,4 @@ -.. include:: ../../components/spi_flash/README.rst - -Application Example -------------------- - -`Instructions`_ - -.. _Instructions: template.html +.. include:: ../../../components/spi_flash/README.rst API Reference ------------- @@ -13,8 +6,9 @@ API Reference Header Files ^^^^^^^^^^^^ - * `spi_flash/include/esp_spi_flash.h `_ - * `spi_flash/include/esp_partition.h `_ + * :component_file:`spi_flash/include/esp_spi_flash.h` + * :component_file:`spi_flash/include/esp_partition.h` + * :component_file:`bootloader_support/include/esp_flash_encrypt.h` Macros ^^^^^^ @@ -23,6 +17,7 @@ Macros .. doxygendefine:: ESP_ERR_FLASH_OP_FAIL .. doxygendefine:: ESP_ERR_FLASH_OP_TIMEOUT .. doxygendefine:: SPI_FLASH_SEC_SIZE +.. doxygendefine:: SPI_FLASH_MMU_PAGE_SIZE .. doxygendefine:: ESP_PARTITION_SUBTYPE_OTA Type Definitions @@ -51,7 +46,9 @@ Functions .. doxygenfunction:: spi_flash_erase_sector .. doxygenfunction:: spi_flash_erase_range .. doxygenfunction:: spi_flash_write +.. doxygenfunction:: spi_flash_write_encrypted .. doxygenfunction:: spi_flash_read +.. doxygenfunction:: spi_flash_read_encrypted .. doxygenfunction:: spi_flash_mmap .. doxygenfunction:: spi_flash_munmap .. doxygenfunction:: spi_flash_mmap_dump @@ -64,4 +61,5 @@ Functions .. doxygenfunction:: esp_partition_write .. doxygenfunction:: esp_partition_erase_range .. doxygenfunction:: esp_partition_mmap +.. doxygenfunction:: esp_flash_encryption_enabled diff --git a/docs/api/vfs.rst b/docs/api/storage/vfs.rst similarity index 69% rename from docs/api/vfs.rst rename to docs/api/storage/vfs.rst index 71550f111c..0035229d83 100644 --- a/docs/api/vfs.rst +++ b/docs/api/storage/vfs.rst @@ -1,9 +1,11 @@ -.. include:: ../../components/vfs/README.rst +.. include:: ../../../components/vfs/README.rst Application Example ------------------- -`Instructions `_ +`Instructions`_ + +.. _Instructions: ../template.html API Reference ------------- @@ -11,8 +13,8 @@ API Reference Header Files ^^^^^^^^^^^^ - * `vfs/include/esp_vfs.h `_ - * `vfs/include/esp_vfs_dev.h `_ + * :component_file:`vfs/include/esp_vfs.h` + * :component_file:`vfs/include/esp_vfs_dev.h` Macros ^^^^^^ diff --git a/docs/api/deep_sleep.rst b/docs/api/system/deep_sleep.rst similarity index 96% rename from docs/api/deep_sleep.rst rename to docs/api/system/deep_sleep.rst index 9e6642fd90..87986026df 100644 --- a/docs/api/deep_sleep.rst +++ b/docs/api/system/deep_sleep.rst @@ -87,3 +87,8 @@ The following function can be used to enter deep sleep once wakeup sources are c .. doxygenfunction:: esp_deep_sleep_start +Application Example +------------------- + +Implementation of basic functionality of deep sleep is shown in :example:`protocols/sntp` example, where ESP module is periodically waken up to retrive time from NTP server. + diff --git a/docs/api/system/index.rst b/docs/api/system/index.rst new file mode 100644 index 0000000000..a7d5d39018 --- /dev/null +++ b/docs/api/system/index.rst @@ -0,0 +1,15 @@ +System API +********** + +.. toctree:: + :maxdepth: 1 + + Memory Allocation + Interrupt Allocation + Watchdogs + OTA + Deep Sleep + Logging + + +Example code for this API section is provided in :example:`system` directory of ESP-IDF examples. diff --git a/docs/api/intr_alloc.rst b/docs/api/system/intr_alloc.rst similarity index 97% rename from docs/api/intr_alloc.rst rename to docs/api/system/intr_alloc.rst index 4d2f21abac..015cc32cd2 100644 --- a/docs/api/intr_alloc.rst +++ b/docs/api/system/intr_alloc.rst @@ -66,7 +66,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `esp_intr_alloc.h `_ + * :component_file:`esp32/include/esp_intr_alloc.h` Macros diff --git a/docs/api/log.rst b/docs/api/system/log.rst similarity index 68% rename from docs/api/log.rst rename to docs/api/system/log.rst index d2f2fcd073..8aadeac095 100644 --- a/docs/api/log.rst +++ b/docs/api/system/log.rst @@ -1,21 +1,21 @@ -.. include:: ../../components/log/README.rst +.. include:: ../../../components/log/README.rst Application Example ------------------- -`Instructions`_ +Log library is commonly used by most of esp-idf components and examples. For demonstration of log functionality check :idf:`examples` folder of `espressif/esp-idf `_ repository, that among others, contains the following examples: + +* :example:`system/ota` +* :example:`storage/sd_card` +* :example:`protocols/https_request` API Reference ------------- -`Instructions`_ - -.. _Instructions: template.html - Header Files ^^^^^^^^^^^^ - * `log/include/esp_log.h `_ + * :component_file:`log/include/esp_log.h` Macros ^^^^^^ diff --git a/docs/api/mem_alloc.rst b/docs/api/system/mem_alloc.rst similarity index 91% rename from docs/api/mem_alloc.rst rename to docs/api/system/mem_alloc.rst index cebea5b8a5..35868f755d 100644 --- a/docs/api/mem_alloc.rst +++ b/docs/api/system/mem_alloc.rst @@ -37,8 +37,8 @@ API Reference Header Files ^^^^^^^^^^^^ - * `esp_heap_alloc_caps.h `_ - * `heap_regions.h `_ + * :component_file:`esp32/include/esp_heap_alloc_caps.h` + * :component_file:`freertos/include/freertos/heap_regions.h` Macros diff --git a/docs/api/ota.rst b/docs/api/system/ota.rst similarity index 75% rename from docs/api/ota.rst rename to docs/api/system/ota.rst index a4984620f6..6ea4ea1f85 100644 --- a/docs/api/ota.rst +++ b/docs/api/system/ota.rst @@ -1,13 +1,18 @@ OTA === +Application Example +------------------- + +Demonstration of OTA (over the air) firmware update workflow: :example:`system/ota`. + API Reference ------------- Header Files ^^^^^^^^^^^^ - * `app_update/include/esp_ota_ops.h `_ + * :component_file:`app_update/include/esp_ota_ops.h` Macros ^^^^^^ diff --git a/docs/api/wdts.rst b/docs/api/system/wdts.rst similarity index 92% rename from docs/api/wdts.rst rename to docs/api/system/wdts.rst index 1b476f2f79..e15ff53dd7 100644 --- a/docs/api/wdts.rst +++ b/docs/api/system/wdts.rst @@ -59,8 +59,8 @@ API Reference Header Files ^^^^^^^^^^^^ - * `esp32/include/esp_int_wdt.h `_ - * `esp32/include/esp_task_wdt.h `_ + * :component_file:`esp32/include/esp_int_wdt.h` + * :component_file:`esp32/include/esp_task_wdt.h` Functions diff --git a/docs/api/ulp.rst b/docs/api/ulp.rst deleted file mode 100644 index 9db42e633e..0000000000 --- a/docs/api/ulp.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../components/ulp/README.rst diff --git a/docs/api/esp_smartconfig.rst b/docs/api/wifi/esp_smartconfig.rst similarity index 76% rename from docs/api/esp_smartconfig.rst rename to docs/api/wifi/esp_smartconfig.rst index 262218aa8b..31295a5d45 100644 --- a/docs/api/esp_smartconfig.rst +++ b/docs/api/wifi/esp_smartconfig.rst @@ -1,5 +1,5 @@ Smart Config -=== +============ API Reference ------------- @@ -7,7 +7,7 @@ API Reference Header Files ^^^^^^^^^^^^ - * `esp32/include/esp_smartconfig.h `_ + * :component_file:`esp32/include/esp_smartconfig.h` Type Definitions ^^^^^^^^^^^^^^^^ diff --git a/docs/api/esp_wifi.rst b/docs/api/wifi/esp_wifi.rst similarity index 89% rename from docs/api/esp_wifi.rst rename to docs/api/wifi/esp_wifi.rst index c13d3d751a..042e810e39 100644 --- a/docs/api/esp_wifi.rst +++ b/docs/api/wifi/esp_wifi.rst @@ -6,22 +6,20 @@ Overview `Instructions`_ +.. _Instructions: ../template.html + Application Example ------------------- -`Instructions`_ +Simple code showing how to connect ESP32 module to an Access Point: `esp-idf-template `_. API Reference ------------- -`Instructions`_ - -.. _Instructions: template.html - Header Files ^^^^^^^^^^^^ - * `esp32/include/esp_wifi.h `_ + * :component_file:`esp32/include/esp_wifi.h` Macros ------ diff --git a/docs/api/wifi/index.rst b/docs/api/wifi/index.rst new file mode 100644 index 0000000000..97165df6b0 --- /dev/null +++ b/docs/api/wifi/index.rst @@ -0,0 +1,11 @@ +Wi-Fi API +********* + +.. toctree:: + :maxdepth: 1 + + Wi-Fi + Smart Config + + +Example code for this API section is provided in :example:`wifi` directory of ESP-IDF examples. diff --git a/docs/build_system.rst b/docs/build-system.rst similarity index 95% rename from docs/build_system.rst rename to docs/build-system.rst index 7a33a41256..b3abbd28f5 100644 --- a/docs/build_system.rst +++ b/docs/build-system.rst @@ -131,7 +131,7 @@ Component Makefiles Each project contains one or more components, which can either be part of esp-idf or added from other component directories. -A component is any sub-directory that contains a `component.mk` file.[#f1]_. +A component is any sub-directory that contains a `component.mk` file [#f1]_. Minimal Component Makefile ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -305,6 +305,17 @@ Second Level: Component Makefiles To better understand the component make process, have a read through the ``component_wrapper.mk`` file and some of the ``component.mk`` files included with esp-idf. +Running Make Non-Interactively +------------------------------ + +When running ``make`` in a situation where you don't want interactive prompts (for example: inside an IDE or an automated build system) append ``BATCH_BUILD=1`` to the make arguments (or set it as an environment variable). + +Setting ``BATCH_BUILD`` implies the following: + +- Verbose output (same as ``V=1``, see below). If you don't want verbose output, also set ``V=0``. +- If the project configuration is missing new configuration items (from new components or esp-idf updates) then the project use the default values, instead of prompting the user for each item. +- If the build system needs to invoke ``menuconfig``, an error is printed and the build fails. + Debugging The Make Process -------------------------- @@ -464,7 +475,7 @@ The file's contents will be added to the .rodata section in flash, and are avail The names are generated from the full name of the file, as given in COMPONENT_EMBED_FILES. Characters /, ., etc. are replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for both text and binary files. -For an example of using this technique, see examples/04_https_request - the certificate file contents are loaded from the text .pem file at compile time. +For an example of using this technique, see :example:`protocols/https_request` - the certificate file contents are loaded from the text .pem file at compile time. Fully Overriding The Component Makefile @@ -485,7 +496,7 @@ is set then the component can instruct the linker to link other binaries instead .. _esp-idf-template: https://github.com/espressif/esp-idf-template .. _GNU Make Manual: https://www.gnu.org/software/make/manual/make.html -.. _[_f1]: Actually, some components in esp-idf are "pure configuration" components that don't have a component.mk file, only a Makefile.projbuild and/or Kconfig.projbuild file. However, these components are unusual and most components have a component.mk file. +.. [#f1] Actually, some components in esp-idf are "pure configuration" components that don't have a component.mk file, only a Makefile.projbuild and/or Kconfig.projbuild file. However, these components are unusual and most components have a component.mk file. Custom sdkconfig defaults diff --git a/docs/conf.py b/docs/conf.py index 551cd86dd0..380a643869 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,30 +14,21 @@ import sys import os +import re +from subprocess import call, Popen, PIPE +import shlex # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('.')) +from repo_util import run_cmd_get_output # -- Run DoxyGen to prepare XML for Sphinx--------------------------------- # ref. https://github.com/rtfd/readthedocs.org/issues/388 -from subprocess import call, Popen, PIPE -import shlex - call('doxygen') -# -- Function to get output of a command ---------------------------------- -def run_cmd_get_output(cmd): - process = Popen(shlex.split(cmd), stdout=PIPE) - (output, err) = process.communicate() - exit_code = process.wait() - if exit_code != 0: - raise RuntimeError('command line program has failed') - return output - - # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -46,7 +37,7 @@ def run_cmd_get_output(cmd): # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['breathe'] +extensions = ['breathe', 'link-roles'] # Breathe extension variables breathe_projects = { "esp32-idf": "xml/" } @@ -65,30 +56,25 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'ESP32 Programming Guide' -copyright = u'2016, Espressif' +project = u'ESP-IDF Programming Guide' +copyright = u'2016 - 2017, Espressif' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # -# Different setup depending if script is running on ReadTheDocs or elsewhere -on_rtd = os.environ.get('READTHEDOCS') == 'True' -if on_rtd: - # The short X.Y version. - # Apparently ReadTheDocs is getting confused by other version / release - # ReadTheDocs is building specific or the latest release from GitHub. - version = '1.0' - release = '1.0' -else: - # This is supposed to be "the short X.Y version", but it's the only version - # visible when you open index.html. - # Display full version to make things less confusing. - # If needed, nearest tag is returned by 'git describe --abbrev=0'. - version = run_cmd_get_output('git describe') - # The full version, including alpha/beta/rc tags. - release = run_cmd_get_output('git describe') +# Readthedocs largely ignores 'version' and 'release', and displays one of +# 'latest', tag name, or branch name, depending on the build type. +# Still, this is useful for non-RTD builds. +# This is supposed to be "the short X.Y version", but it's the only version +# visible when you open index.html. +# Display full version to make things less confusing. +version = run_cmd_get_output('git describe') +# The full version, including alpha/beta/rc tags. +# If needed, nearest tag is returned by 'git describe --abbrev=0'. +release = version +print 'Version: {0} Release: {1}'.format(version, release) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/contributor-agreement.rst b/docs/contributor-agreement.rst index a7919da8f8..aac25ad4fd 100644 --- a/docs/contributor-agreement.rst +++ b/docs/contributor-agreement.rst @@ -12,8 +12,8 @@ Framework (esp-idf) ("We" or "Us"). The purpose of this contributor agreement ("Agreement") is to clarify and document the rights granted by contributors to Us. To make this -document effective, please follow the instructions at -https://github.com/espressif/esp-idf/blob/master/CONTRIBUTING.rst. +document effective, please follow the instructions at +:idf_file:`CONTRIBUTING.rst` 1. DEFINITIONS ~~~~~~~~~~~~~~ diff --git a/docs/core_dump.rst b/docs/core_dump.rst index a8e328996f..47cfd89c07 100644 --- a/docs/core_dump.rst +++ b/docs/core_dump.rst @@ -16,13 +16,18 @@ ESP-IDF provides special script `espcoredump.py` to help users to retrieve and a Configuration ------------- -Currently there are three options related to core dump generation which user can choose in configuration menu of the application (`make menuconfig`): +There are a number of core dump related configuration options which user can choose in configuration menu of the application (`make menuconfig`). + +1. Core dump data destination (`Components -> ESP32-specific config -> Core dump destination`): * Disable core dump generation * Save core dump to flash * Print core dump to UART -These options can be choosen in Components -> ESP32-specific config -> Core dump destination menu item. +2. Logging level of core dump module (`Components -> ESP32-specific config -> Core dump module logging level`). Value is a number from 0 (no output) to 5 (most verbose). + +3. Delay before core dump will be printed to UART (`Components -> ESP32-specific config -> Core dump print to UART delay`). Value is in ms. + Save core dump to flash ----------------------- @@ -49,8 +54,8 @@ Print core dump to UART ----------------------- When this option is selected base64-encoded core dumps are printed on UART upon system panic. In this case user should save core dump text body to some file manually and -then run the following command: `espcoredump.py -p info_corefile -t b64 -c ` -or `espcoredump.py -p dbg_corefile -t b64 -c ` +then run the following command: `espcoredump.py info_corefile -t b64 -c ` +or `espcoredump.py dbg_corefile -t b64 -c ` Base64-encoded body of core dump will be between the following header and footer:: diff --git a/docs/documenting-code.rst b/docs/documenting-code.rst index a73e26de4b..a201dafb8c 100644 --- a/docs/documenting-code.rst +++ b/docs/documenting-code.rst @@ -135,7 +135,7 @@ OK, but I am new to Sphinx! --------------------------- 1. No worries. All the software you need is well documented. It is also open source and free. Start by checking `Sphinx `_ documentation. If you are not clear how to write using rst markup language, see `reStructuredText Primer `_. -2. Check the source files of this documentation to understand what is behind of what you see now on the screen. Sources are maintained on GitHub in `espressif/esp-idf`_ repository in `/docs `_ folder. You can go directly to the source file of this page by scrolling up and clicking the link in the top right corner. When on GitHub, see what's really inside, open source files by clicking ``Raw`` button. +2. Check the source files of this documentation to understand what is behind of what you see now on the screen. Sources are maintained on GitHub in `espressif/esp-idf`_ repository in :idf:`docs` folder. You can go directly to the source file of this page by scrolling up and clicking the link in the top right corner. When on GitHub, see what's really inside, open source files by clicking ``Raw`` button. 3. You will likely want to see how documentation builds and looks like before posting it on the GitHub. There are two options to do so: * Install `Sphinx `_, `Breathe `_ and `Doxygen `_ to build it locally. You would need a Linux machine for that. diff --git a/docs/eclipse-setup-windows.rst b/docs/eclipse-setup-windows.rst new file mode 100644 index 0000000000..aeb011c0c1 --- /dev/null +++ b/docs/eclipse-setup-windows.rst @@ -0,0 +1,77 @@ +Eclipse IDE on Windows +********************** + +Configuring Eclipse on Windows requires some different steps. The full configuration steps for Windows are shown below. + +(For OS X and Linux instructions, see the :doc:`Eclipse IDE page `.) + +Installing Eclipse IDE +====================== + +Follow the steps under :ref:`Installing Eclipse IDE ` for all platforms. + +.. _eclipse-windows-setup: + +Setting up Eclipse on Windows +============================= + +Once your new Eclipse installation launches, follow these steps: + +Import New Project +------------------ + +* Eclipse makes use of the Makefile support in ESP-IDF. This means you need to start by creating an ESP-IDF project. You can use the idf-template project from github, or open one of the examples in the esp-idf examples subdirectory. + +* Once Eclipse is running, choose File -> Import... + +* In the dialog that pops up, choose "C/C++" -> "Existing Code as Makefile Project" and click Next. + +* On the next page, enter "Existing Code Location" to be the directory of your IDF project. Don't specify the path to the ESP-IDF directory itself (that comes later). The directory you specify should contain a file named "Makefile" (the project Makefile). + +* On the same page, under "Toolchain for Indexer Settings" uncheck "Show only available toolchains that support this platform". + +* On the extended list that appears, choose "Cygwin GCC". Then click Finish. + +*Note: you may see warnings in the UI that Cygwin GCC Toolchain could not be found. This is OK, we're going to reconfigure Eclipse to find our toolchain.* + +Project Properties +------------------ + +* The new project will appear under Project Explorer. Right-click the project and choose Properties from the context menu. + +* Click on the "C/C++ Build" properties page (top-level): + + * Uncheck "Use default build command" and enter this for the custom build command: ``python ${IDF_PATH}/tools/windows/eclipse_make.py``. + +* Click on the "Environment" properties page under "C/C++ Build": + + * Click "Add..." and enter name ``BATCH_BUILD`` and value ``1``. + + * Click "Add..." again, and enter name ``IDF_PATH``. The value should be the full path where ESP-IDF is installed. The IDF_PATH directory should be specified using forwards slashes not backslashes, ie *C:/Users/MyUser/Development/esp-idf*. + + * Edit the PATH environment variable. Delete the existing value and replace it with ``C:\msys32\usr\bin;C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin`` (If you installed msys32 to a different directory then you'll need to change these paths to match). + +* Click on "C/C++ General" -> "Preprocessor Include Paths, Macros,etc." property page: + + * Click the "Providers" tab + + * In the list of providers, click "CDT GCC Built-in Compiler Settings Cygwin". Under "Command to get compiler specs", replace the text ``${COMMAND}`` at the beginning of the line with ``xtensa-esp32-elf-gcc``. This means the full "Command to get compiler specs" should be ``xtensa-esp32-elf-gcc ${FLAGS} -E -P -v -dD "${INPUTS}"``. + + * In the list of providers, click "CDT GCC Build Output Parser" and type ``xtensa-esp32-elf-`` at the beginning of the Compiler command pattern. This means the full Compiler command pattern should be ``xtensa-esp32-elf-(g?cc)|([gc]\+\+)|(clang)`` + + +Building in Eclipse +------------------- + +Continue from :ref:`Building in Eclipse ` for all platforms. + +Technical Details +================= + +**Of interest to Windows gurus or very curious parties, only.** + +Explanations of the technical reasons for some of these steps. You don't need to know this in order to use esp-idf with Eclipse on Windows, but it may be helpful background knowledge if you plan to do dig into the Eclipse support: + +* The xtensa-esp32-elf-gcc cross-compiler is *not* a Cygwin toolchain, even though we tell Eclipse that it is one. This is because msys2 uses Cygwin and supports Cygwin paths (of the type ``/c/blah`` instead of ``c:/blah`` or ``c:\\blah``). In particular, xtensa-esp32-elf-gcc reports to the Eclipse "built-in compiler settings" function that its built-in include directories are all under ``/usr/``, which is a Unix/Cygwin-style path that Eclipse otherwise can't resolve. By telling Eclipse the compiler is Cygwin, it resolves these paths internally using the ``cygpath`` utility. + +* The same problem occurs when parsing make output from esp-idf. Eclipse parses this output to find header directories, but it can't resolve include directories of the form ``/c/blah`` without using ``cygpath``. There is a heuristic that Eclipse Build Output Parser uses to determine whether it should call ``cygpath``, but for currently unknown reasons the esp-idf configuration doesn't trigger it. For this reason the ``eclipse_make.py`` wrapper script is used to call ``make`` and then use ``cygpath`` to process the output for Eclipse. diff --git a/docs/eclipse-setup.rst b/docs/eclipse-setup.rst index fbad93be6c..140e81e173 100644 --- a/docs/eclipse-setup.rst +++ b/docs/eclipse-setup.rst @@ -1,6 +1,8 @@ Build and Flash with Eclipse IDE ******************************** +.. _eclipse-install-steps: + Installing Eclipse IDE ====================== @@ -8,10 +10,17 @@ The Eclipse IDE gives you a graphical integrated development environment for wri * Start by installing the esp-idf for your platform (see files in this directory with steps for Windows, OS X, Linux). +* We suggest building a project from the command line first, to get a feel for how that process works. You also need to use the command line to configure your esp-idf project (via ``make menuconfig``), this is not currently supported inside Eclipse. + * Download the Eclipse Installer for your platform from eclipse.org_. * When running the Eclipse Installer, choose "Eclipse for C/C++ Development" (in other places you'll see this referred to as CDT.) +Windows Users +============= + +Using ESP-IDF with Eclipse on Windows requires different configuration steps. :ref:`See the Eclipse IDE on Windows guide `. + Setting up Eclipse ================== @@ -20,13 +29,13 @@ Once your new Eclipse installation launches, follow these steps: Import New Project ------------------ -* Eclipse makes use of the Makefile support in ESP-IDF. This means you need to start by creating an ESP-IDF project. You can use the skeleton project from github. +* Eclipse makes use of the Makefile support in ESP-IDF. This means you need to start by creating an ESP-IDF project. You can use the idf-template project from github, or open one of the examples in the esp-idf examples subdirectory. * Once Eclipse is running, choose File -> Import... * In the dialog that pops up, choose "C/C++" -> "Existing Code as Makefile Project" and click Next. -* On the next page, enter "Existing Code Location" to be the directory of your IDF project. Don't specify the path to the ESP-IDF directory itself. +* On the next page, enter "Existing Code Location" to be the directory of your IDF project. Don't specify the path to the ESP-IDF directory itself (that comes later). The directory you specify should contain a file named "Makefile" (the project Makefile). * On the same page, under "Toolchain for Indexer Settings" choose "Cross GCC". Then click Finish. @@ -36,15 +45,9 @@ Project Properties * The new project will appear under Project Explorer. Right-click the project and choose Properties from the context menu. -* Click on the "Environment" properties page under "C/C++ Build". Click "Add..." and enter name ``V`` and value ``1``. +* Click on the "Environment" properties page under "C/C++ Build". Click "Add..." and enter name ``BATCH_BUILD`` and value ``1``. -* Click "Add..." again, and enter name ``IDF_PATH``. The value should be the full path where ESP-IDF is installed. *Windows users: Use forward-slashes not backslashes for this path, ie C:/Users/MyUser/Development/esp-idf*. - -*Windows users only, follow these two additional steps:* - -* On the same Environment property page, edit the PATH environment variable. Delete the existing value and replace it with ``C:\msys32\usr\bin;C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin`` (If you installed msys32 to a different directory then you'll need to change these paths to match). - -* Click on the "C/C++ Build" top-level properties page then uncheck "Use default build command" and enter this for the custom build command: ``bash ${IDF_PATH}/tools/windows/eclipse_make.sh``. +* Click "Add..." again, and enter name ``IDF_PATH``. The value should be the full path where ESP-IDF is installed. *All users, continue with these steps:* @@ -56,7 +59,22 @@ Navigate to "C/C++ General" -> "Preprocessor Include Paths" property page: * In the list of providers, click "CDT GCC Build Output Parser" and type ``xtensa-esp32-elf-`` at the beginning of the Compiler command pattern. This means the full Compiler command pattern should be ``xtensa-esp32-elf-(g?cc)|([gc]\+\+)|(clang)`` -* Click OK to close the Properties dialog, and choose Project -> Build to build your project. +.. _eclipse-build-project: + +Building in Eclipse +------------------- + +Before your project is first built, Eclipse may show a lot of errors and warnings about undefined values. This is because some source files are automatically generated as part of the esp-idf build process. These errors and warnings will go away after you build the project. + +* Click OK to close the Properties dialog in Eclipse. + +* Outside Eclipse, open a command line prompt. Navigate to your project directory, and run ``make menuconfig`` to configure your project's esp-idf settings. This step currently has to be run outside Eclipse. + +*If you try to build without running a configuration step first, esp-idf will prompt for configuration on the command line - but Eclipse is not able to deal with this, so the build will hang or fail.* + +* Back in Eclipse, choose Project -> Build to build your project. + +**TIP**: If your project had already been built outside Eclipse, you may need to do a Project -> Clean before chosing Project -> Build. This is so Eclipse can see the compiler arguments for all source files. It uses these to determine the header include paths. Flash from Eclipse ------------------ @@ -77,7 +95,3 @@ Follow the same steps to add ``bootloader`` and ``partition_table`` targets, if .. _eclipse.org: http://www.eclipse.org/ -Eclipse Troubleshooting ------------------------ - -* ``*** Make was invoked from ... However please do not run make from the sdk or a component directory; ...`` - Eclipse will detect any directory with a Makefile in it as being a possible directory to run "make" in. All component directories also contain a Makefile (the wrong one), so it is important when using Project -> Make Target to always select the top-level project directory in Project Explorer. diff --git a/docs/general-notes.rst b/docs/general-notes.rst index a683467007..6597337a1e 100644 --- a/docs/general-notes.rst +++ b/docs/general-notes.rst @@ -100,7 +100,7 @@ The code which has to run after wake-up from deep sleep mode has to be placed in DRAM (data RAM) ^^^^^^^^^^^^^^^ -Non-constant static data and zero-initialized data is placed by the linker into 200 kB ``0x3FFB0000 — 0x3FFF0000`` region. Note that this region is reduced by 64kB (by shifting start address to ``0x3FFC0000``) if Bluetooth stack is used. Length of this region is also reduced by 16 kB or 32kB if trace memory is used. All space which is left in this region after placing static data there is used for the runtime heap. +Non-constant static data and zero-initialized data is placed by the linker into the 256 kB ``0x3FFB0000 — 0x3FFF0000`` region. Note that this region is reduced by 64kB (by shifting start address to ``0x3FFC0000``) if Bluetooth stack is used. Length of this region is also reduced by 16 kB or 32kB if trace memory is used. All space which is left in this region after placing static data there is used for the runtime heap. Constant data may also be placed into DRAM, for example if it is used in an ISR handler (see notes in IRAM section above). To do that, ``DRAM_ATTR`` define can be used:: diff --git a/docs/index.rst b/docs/index.rst index eafe102447..4beb326285 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,118 +26,47 @@ Contents: .. toctree:: :caption: What Else? :maxdepth: 1 - - General Notes - partition-tables - build_system - openocd - core_dump - Flash encryption - Secure Boot - ULP coprocessor -.. API Reference - .. - Table of Contents Outline - .. - 1. System - TBA - 1.1. Fundamentals of multiprocessor programming with FreeRTOS - TBA - 1.2. Application startup flow - TBA - 1.3. Flash encryption and secure boot: how they work and APIs - 1.4. Lower Power Coprocessor - TBA - 1.5. Watchdogs - 1.6. Memory allocation - 1.7. ... - 2. Memory - TBA - 2.1. Memory layout of the application (IRAM/IROM, limitations of each) - TBA - 2.2. Flash layout and partitions - TBA - 2.3. Flash access APIs - TBA - 2.4. Partition APIs - TBA - 2.5. OTA mechanism (app partitions, OTA partition) and APIs - TBA - 2.6. ... - 3. Wi-Fi - 4. Bluetooth - 4.1. BT Classic - TBA - 4.2. BLE - 5. Ethernet - TBA - 6. Interfaces - 6.1. GPIO - 6.2. ADC - TBA - 6.3. DAC - TBA - 6.4. UART - 6.5. I2C - TBA - 6.6. I2S - TBA - 6.7. SPI - - 6.8. CAN - TBA - 6.9. SD Controller - TBA - 6.10. Infrared - TBA - 6.11. Pulse Counter - TBA - 6.12. PWM - TBA - 6.13. LED PWM - 6.14. ... - 7. Sensors - TBA - 7.1. Hall Sensor - TBA - 7.2. Temperature Sensor - TBA - 7.3. Touch Sensor - TBA - 8. Protocols - TBA - 9. Components - 9.1. Logging - 9.2 Non-Volatile Storage - 9.3 Virtual Filesystem - 9.3. Http sever - TBA - 10. Applications - TBA - .. - API Dcoumentation Teamplate - .. + General Notes + Build System + Debugging + ESP32 Core Dump + Partition Tables + Flash Encryption + Secure Boot + Deep Sleep Wake Stubs + ULP Coprocessor + Unit Testing .. toctree:: :caption: API Reference - :maxdepth: 1 + :maxdepth: 2 - Wi-Fi - Smart Config - Bluetooth - Watchdogs - OTA - GPIO - UART - LED Control - Remote Control - Timer - I2C - Pulse Counter - Sigma-delta Modulation - SD/MMC - SPI Flash and Partition APIs - SPI Master API - Logging - Non-Volatile Storage - Virtual Filesystem - FAT Filesystem - Ethernet - Interrupt Allocation - Memory Allocation - Deep Sleep - deep-sleep-stub - - mDNS - Template + Wi-Fi + Bluetooth + Ethernet + Peripherals + System + Storage + Protocols .. toctree:: - :caption: Technical Reference + :caption: Hardware Reference - Technical Reference - -.. Resources - TBA + Technical Reference Manual (PDF) + Pin List and Functions (PDF) + Chip Pinout (PDF) + Silicon Errata (PDF) .. toctree:: :caption: Contribute :maxdepth: 1 - contributing + Contributions Guide Style Guide - documenting-code - contributor-agreement + Documenting Code + API Template + Contributor Agreement .. toctree:: :caption: Legal @@ -147,8 +76,6 @@ Contents: Indices -------- +======= * :ref:`genindex` -* :ref:`search` - diff --git a/docs/link-roles.py b/docs/link-roles.py new file mode 100644 index 0000000000..e774721922 --- /dev/null +++ b/docs/link-roles.py @@ -0,0 +1,34 @@ +# based on http://protips.readthedocs.io/link-roles.html + +from docutils import nodes +from repo_util import run_cmd_get_output + +def get_github_rev(): + path = run_cmd_get_output('git rev-parse --short HEAD') + tag = run_cmd_get_output('git describe --exact-match') + print 'Git commit ID: ', path + if len(tag): + print 'Git tag: ', tag + path = tag + return path + + +def setup(app): + baseurl = 'https://github.com/espressif/esp-idf' + rev = get_github_rev() + app.add_role('idf', autolink('{}/tree/{}/%s'.format(baseurl, rev))) + app.add_role('idf_file', autolink('{}/blob/{}/%s'.format(baseurl, rev))) + app.add_role('idf_raw', autolink('{}/raw/{}/%s'.format(baseurl, rev))) + app.add_role('component', autolink('{}/tree/{}/components/%s'.format(baseurl, rev))) + app.add_role('component_file', autolink('{}/blob/{}/components/%s'.format(baseurl, rev))) + app.add_role('component_raw', autolink('{}/raw/{}/components/%s'.format(baseurl, rev))) + app.add_role('example', autolink('{}/tree/{}/examples/%s'.format(baseurl, rev))) + app.add_role('example_file', autolink('{}/blob/{}/examples/%s'.format(baseurl, rev))) + app.add_role('example_raw', autolink('{}/raw/{}/examples/%s'.format(baseurl, rev))) + +def autolink(pattern): + def role(name, rawtext, text, lineno, inliner, options={}, content=[]): + url = pattern % (text,) + node = nodes.reference(rawtext, text, refuri=url, **options) + return [node], [] + return role diff --git a/docs/make-project.rst b/docs/make-project.rst index e72bb81dd0..0bfac801bb 100644 --- a/docs/make-project.rst +++ b/docs/make-project.rst @@ -4,7 +4,7 @@ Build and Flash with Make Finding a project ----------------- -As well as the `esp-idf-template `_ project mentioned in the setup guide, esp-idf comes with some example projects on github in the `examples `_ directory. +As well as the `esp-idf-template `_ project mentioned in the setup guide, ESP-IDF comes with some example projects on github in the :idf:`examples` directory. Once you've found the project you want to work with, change to its directory and you can configure and build it: diff --git a/docs/repo_util.py b/docs/repo_util.py new file mode 100644 index 0000000000..6249c11df1 --- /dev/null +++ b/docs/repo_util.py @@ -0,0 +1,5 @@ +import re +import os + +def run_cmd_get_output(cmd): + return os.popen(cmd).read().strip() diff --git a/docs/security/flash-encryption.rst b/docs/security/flash-encryption.rst index 298a0a75bf..8448f020bd 100644 --- a/docs/security/flash-encryption.rst +++ b/docs/security/flash-encryption.rst @@ -3,9 +3,9 @@ Flash Encryption Flash Encryption is a feature for encrypting the contents of the ESP32's attached SPI flash. When flash encryption is enabled, physical readout of the SPI flash is not sufficient to recover most flash contents. -Flash Encryption is separate from the `Secure Boot` feature, and you can use flash encryption without enabling secure boot. However we recommend using both features together for a secure environment. +Flash Encryption is separate from the :doc:`Secure Boot ` feature, and you can use flash encryption without enabling secure boot. However we recommend using both features together for a secure environment. -**IMPORTANT: Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including `Limitations of Flash Encryption` and understand the implications of enabling flash encryption.** +**IMPORTANT: Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including :ref:`flash-encryption-limitations`) and understand the implications of enabling flash encryption.** Background ---------- @@ -17,6 +17,7 @@ Background - Encryption is applied by flashing the ESP32 with plaintext data, and (if encryption is enabled) the bootloader encrypts the data in place on first boot. - Not all of the flash is encrypted. The following kinds of flash data are encrypted: + - Bootloader - Secure boot bootloader digest (if secure boot is enabled) - Partition Table @@ -29,58 +30,75 @@ Background - The `flash encryption algorithm` is AES-256, where the key is "tweaked" with the offset address of each 32 byte block of flash. This means every 32 byte block (two consecutive 16 byte AES blocks) is encrypted with a unique key derived from the flash encryption key. -- Although software running on the chip can transparently decrypt flash contents, by default it is made possible for the UART bootloader to decrypt (or encrypt) data when flash encryption is enabled. +- Although software running on the chip can transparently decrypt flash contents, by default it is made impossible for the UART bootloader to decrypt (or encrypt) data when flash encryption is enabled. + +- If flash encrption may be enabled, the programmer must take certain precautions when writing code that :ref:`uses encrypted flash `. + +.. _flash-encryption-initialisation: Flash Encryption Initialisation ------------------------------- -This is the default (and recommended) flash encryption initialisation process. It is possible to customise this process for development or other purposes, see `Flash Encryption Advanced Features` for details. +This is the default (and recommended) flash encryption initialisation process. It is possible to customise this process for development or other purposes, see :ref:`flash-encryption-advanced-features` for details. -**IMPORTANT: Once flash encryption is enabled on first boot, the hardware allows a maximum of 3 subsequent flash updates via physical re-flashing. If secure boot is enabled, no physical re-flashes are possible. OTA updates can be used to update flash content without counting towards this limit. When enabling flash encryption in development, use a `precalculated flash encryption key` to allow physically re-flashing an unlimited number of times with pre-encrypted data.** +**IMPORTANT: Once flash encryption is enabled on first boot, the hardware allows a maximum of 3 subsequent flash updates via serial re-flashing.** A special procedure (documented in :ref:`updating-encrypted-flash-serial`) must be followed to perform these updates. -- The bootloader must be compiled with flash encryption support enabled. In ``make menuconfig``, navigate to "Security Features" and select "Yes" for "Enable flash nencryption on boot". +- If secure boot is enabled, no physical re-flashes are possible. +- OTA updates can be used to update flash content without counting towards this limit. +- When enabling flash encryption in development, use a `pregenerated flash encryption key` to allow physically re-flashing an unlimited number of times with pre-encrypted data.** -- If enabling Secure Boot at the same time, you can simultaneously select those options now. See the `Secure Boot` documentation for details. +Process to enable flash encryption: + +- The bootloader must be compiled with flash encryption support enabled. In ``make menuconfig``, navigate to "Security Features" and select "Yes" for "Enable flash encryption on boot". + +- If enabling Secure Boot at the same time, it is best to simultaneously select those options now. Read the :doc:`Secure Boot ` documentation first. - Build and flash the bootloader, partition table and factory app image as normal. These partitions are initially written to the flash unencrypted. -- On first boot, the bootloader sees ``FLASH_CRYPT_CNT`` efuse is set to 0 so it generates a flash encryption key using the hardware random number generator. This key is stored in efuse. The key is read and write protected against further software access. +- On first boot, the bootloader sees :ref:`FLASH_CRYPT_CNT` is set to 0 (factory default) so it generates a flash encryption key using the hardware random number generator. This key is stored in efuse. The key is read and write protected against further software access. - All of the encrypted partitions are then encrypted in-place by the bootloader. Encrypting in-place can take some time (up to a minute for large partitions.) -**IMPORTANT: Do not interrupt power to the ESP32 while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and require flashing with unencrypted data again. This re-flash will not count towards the flashing limit, as ``FLASH_CRYPT_CNT`` is only updated after this process finishes.** +**IMPORTANT: Do not interrupt power to the ESP32 while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and require flashing with unencrypted data again. A reflash like this will not count towards the flashing limit.** -- Once flashing is complete. efuses are blown (by default) to disable encrypted flash access while the UART bootloader is running. +- Once flashing is complete. efuses are blown (by default) to disable encrypted flash access while the UART bootloader is running. See :ref:`uart-bootloader-encryption` for advanced details. -- If not already write-protected, the ``FLASH_CRYPT_CONFIG`` efuse is also burned to the maximum value (``0xF``) to maximise the number of key bits which are tweaked in the flash algorithm. See `Setting FLASH_CRYPT_CONFIG` for details of this efuse. +- The ``FLASH_CRYPT_CONFIG`` efuse is also burned to the maximum value (``0xF``) to maximise the number of key bits which are tweaked in the flash algorithm. See :ref:`setting-flash-crypt-config` for advanced details. -- Finally, the ``FLASH_CRYPT_CNT`` efuse is burned with the initial value 1. It is this efuse which activates the transparent flash encryption layer, and limits the number of subsequent reflashes. See the `Updating Encrypted Flash` section for details about ``FLASH_CRYPT_CNT``. +- Finally, the :ref:`FLASH_CRYPT_CNT` is burned with the initial value 1. It is this efuse which activates the transparent flash encryption layer, and limits the number of subsequent reflashes. See the :ref:`updating-encrypted-flash` section for details about :ref:`FLASH_CRYPT_CNT`. - The bootloader resets itself to reboot from the newly encrypted flash. +.. _using-encrypted-flash: -Encrypted Flash Access ----------------------- +Using Encrypted Flash +--------------------- -Reading Encrypted Flash -^^^^^^^^^^^^^^^^^^^^^^^ +ESP32 app code can check if flash encryption is currently enabled by calling :func:`esp_flash_encryption_enabled`. -Whenever the ``FLASH_CRYPT_CNT`` efuse is set to a value with an odd number of bits set, all flash content which is accessed via the MMU's flash cache is transparently decrypted. This includes: +Once flash encryption is enabled, some care needs to be taken when accessing flash contents from code. + +Scope of Flash Encryption +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Whenever the :ref:`FLASH_CRYPT_CNT` is set to a value with an odd number of bits set, all flash content which is accessed via the MMU's flash cache is transparently decrypted. This includes: - Executable application code in flash (IROM). - All read-only data stored in flash (DROM). -- Any data accessed via ``esp_spi_flash_mmap``. +- Any data accessed via :func:`esp_spi_flash_mmap`. - The software bootloader image when it is read by the ROM bootloader. **IMPORTANT: The MMU flash cache unconditionally decrypts all data. Data which is stored unencrypted in the flash will be "transparently decrypted" via the flash cache and appear to software like random garbage.** -To read data without using a flash cache MMU mapping, we recommend using the partition read function ``esp_partition_read``. When using this function, data will only be decrypted when it is read from an encrypted partition. Other partitions will be read unencrypted. In this way, software can access encrypted and non-encrypted flash in the same way. +Reading Encrypted Flash +^^^^^^^^^^^^^^^^^^^^^^^ +To read data without using a flash cache MMU mapping, we recommend using the partition read function :func:`esp_partition_read`. When using this function, data will only be decrypted when it is read from an encrypted partition. Other partitions will be read unencrypted. In this way, software can access encrypted and non-encrypted flash in the same way. Data which is read via other SPI read APIs are not decrypted: -- Data read via ``esp_spi_flash_read`` is not decrypted -- Data read via ROM function ``SPIRead`` is not decrypted (this function is not supported in esp-idf apps). -- Data stored using the Non-Volatile Storage (NVS) API is always stored decrypted. +- Data read via :func:`esp_spi_flash_read` is not decrypted +- Data read via ROM function :func:`SPIRead` is not decrypted (this function is not supported in esp-idf apps). +- Data stored using the Non-Volatile Storage (NVS) API is always stored and read decrypted. Writing Encrypted Flash @@ -92,92 +110,179 @@ The ``esp_spi_flash_write`` function will write data when the write_encrypted pa The ROM function ``SPI_Encrypt_Write`` will write encrypted data to flash, the ROM function ``SPIWrite`` will write unencrypted to flash. (these function are not supported in esp-idf apps). -The minimum write size for unencrypted data is 4 bytes (and the alignment is 4 bytes). Because data is encrypted in blocks, the minimum write size for encrypted data is 32 bytes (and the alignment is 32 bytes.) +The minimum write size for unencrypted data is 4 bytes (and the alignment is 4 bytes). Because data is encrypted in blocks, the minimum write size for encrypted data is 16 bytes (and the alignment is 16 bytes.) + +.. _updating-encrypted-flash: Updating Encrypted Flash ------------------------ +.. _updating-encrypted-flash-ota: + OTA Updates ^^^^^^^^^^^ OTA updates to encrypted partitions will automatically write encrypted, as long as the ``esp_partition_write`` function is used. +.. _updating-encrypted-flash-serial: + Serial Flashing ^^^^^^^^^^^^^^^ -Provided secure boot is not used, the ``FLASH_CRYPT_CNT`` registers allow the flash to be updated with new plaintext data via serial flashing (or other physical methods), up to 3 additional times. ``FLASH_CRYPT_CNT`` efuse is an 8-bit value, and the flash encryption enables or disables based on the number of bits which are set to "1": +Provided secure boot is not used, the :ref:`FLASH_CRYPT_CNT` allows the flash to be updated with new plaintext data via serial flashing (or other physical methods), up to 3 additional times. -- Even number (0-6) bits are set: Transparent reading of encrypted flash is disabled, any encrypted data cannot be decrypted. If the bootloader was built with "Enable flash encryption on boot" then it will see this situation and immediately re-encrypt the flash wherever it finds unencrypted data. Once done, it sets another bit in the efuse to '1' meaning an odd number of bits are now set. - -- Odd number (1-7) bits are set: Transparent reading of encrypted flash is enabled. - -- All 8 bits are set (valuye 0: Transparent reading of encrypted flash is disabled, any encrypted data is inaccessible. Bootloader will normally detect this condition and halt. To avoid use of this state to load unauthorised code, secure boot must be used or ``FLASH_CRYPT_CNT`` must be write-protected. - -The espefuse.py tool can be used to manually change the number of bits set in ``FLASH_CRYPT_CNT``, via serial bootloader. +The process involves flashing plaintext data, and then bumping the value of :ref:`FLASH_CRYPT_CNT` which causes the bootloader to re-encrypt this data. Limited Updates -^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~ -Only 4 physical flash updates (writing plaintext data which is then encrypted) are possible: +Only 4 serial flash update cycles of this kind are possible, including the initial encrypted flash. -1. On first plaintext boot, bit count has brand new value 0 and bootloader changes to 1 (0x01) following encryption. -2. On next plaintext flash update, bit count is manually updated to 2 (0x03) and bootloader changes to 4 (0x07) following encryption. -3. Then bit count is manually updated to 4 (0x0F) and the bootloader changes efuse bit count to 5 (0x1F). -4. Finally bootloader is manually updated to 6 (0x3F) and bootloader changes efuse bit count to 7 (0x7F). +After the fourth time encryption is disabled, :ref:`FLASH_CRYPT_CNT` has the maximum value `0xFF` and encryption is permanently disabled. -Cautions With Re-Flashing -^^^^^^^^^^^^^^^^^^^^^^^^^^ +Using :ref:`updating-encrypted-flash-ota` or :ref:`pregenerated-flash-encryption-key` allows you to exceed this limit. -- When reflashing via serial, reflash every partition that was previously written with plaintext (including bootloader). It is possible to skip app partitions which are not the "currently selected" OTA partition (these will not be re-encrypted unless a plaintext app image is found there.) However any partition marked with the "encrypt" flag will be unconditionally re-encrypted, meaning that any already encrypted data will be encrypted twice and corrupted. +Cautions With Serial Flashing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- If secure boot is enabled, you can't reflash via serial at all unless you used chosen the "Reflashable" option for Secure Boot, pre-generated a key and burned it to the ESP32. In this case you can re-flash a plaintext secure boot digest and bootloader image at offset 0 (see `Secure Boot` documentation.) In production secure boot configuration, the secure boot digest is stored encrypted - so if ``FLASH_CRYPT_CNT`` is set to an even value then the ROM bootloader will read the encrypted digest as-is and therefore will fail to verify any bootloader image as valid. +- When reflashing via serial, reflash every partition that was initially written with plaintext data (including bootloader). It is possible to skip app partitions which are not the "currently selected" OTA partition (these will not be re-encrypted unless a plaintext app image is found there.) However any partition marked with the "encrypt" flag will be unconditionally re-encrypted, meaning that any already encrypted data will be encrypted twice and corrupted. -Re-Flashing Procedure -^^^^^^^^^^^^^^^^^^^^^ + - Using ``make flash`` should flash all partitions which need to be flashed. -The steps to update a device with plaintext via UART bootloader, when flash encryption is enabled are: +- If secure boot is enabled, you can't reflash via serial at all unless you used the "Reflashable" option for Secure Boot, pre-generated a key and burned it to the ESP32 (refer to :doc:`Secure Boot ` docs.). In this case you can re-flash a plaintext secure boot digest and bootloader image at offset 0x0. It is necessary to re-flash this digest before flashing other plaintext data. + +Serial Re-Flashing Procedure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Build the application as usual. -- Burn the ``FLASH_CRYPT_CNT`` efuse by running the command ``espefuse.py burn_efuse FLASH_CRYPT_CNT``. espefuse.py will automatically increment the bit count by 1. +- Flash the device with plaintext data as usual (``make flash`` or ``esptool.py`` commands.) Flash all previously encrypted partitions, including the bootloader (see previous section). -- Flash the device with plaintext data as usual (``make flash`` or ``esptool.py`` commands.) Flash all previously encrypted partitions, including the bootloader. If secure boot is enabled, it must be enabled in "Reflashable" mode and a pre-generated key burned to the ESP32 - flash the bootloader-reflash-digest.bin file at offset 0x0. +- At this point, the device will fail to boot (message is ``flash read err, 1000``) because it expects to see an encrypted bootloader, but the bootloader is plaintext. -- Reset the device and it will re-encrypt plaintext partitions, burn the ``FLASH_CRYPT_CNT`` flag to re-enable encryption. +- Burn the :ref:`FLASH_CRYPT_CNT` by running the command ``espefuse.py burn_efuse FLASH_CRYPT_CNT``. espefuse.py will automatically increment the bit count by 1, which disables encryption. + +- Reset the device and it will re-encrypt plaintext partitions, then burn the :ref:`FLASH_CRYPT_CNT` again to re-enable encryption. -Disabling Updates -^^^^^^^^^^^^^^^^^ +Disabling Serial Updates +~~~~~~~~~~~~~~~~~~~~~~~~ -To prevent further plaintext updates via physical access, use espefuse.py to write protect the ``FLASH_CRYPT_CNT`` efuse after flash encryption has been enabled (ie after first boot is complete):: +To prevent further plaintext updates via serial, use espefuse.py to write protect the :ref:`FLASH_CRYPT_CNT` after flash encryption has been enabled (ie after first boot is complete):: - espefuse.py write_protect_efuse FLASH_CRYPT_CNT + espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT This prevents any further modifications to disable or re-enable flash encryption. +.. _pregenerated-flash-encryption-key: + +Reflashing via Pregenerated Flash Encryption Key +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is possible to pregenerate a flash encryption key on the host computer and burn it into the ESP32's efuse key block. This allows data to be pre-encrypted on the host and flashed to the ESP32 without needing a plaintext flash update. + +This is useful for development, because it removes the 4 time reflashing limit. It also allows reflashing with secure boot enabled, because the bootloader doesn't need to be reflashed each time. + +**IMPORTANT This method is intended to assist with development only, not for production devices. If pre-generating flash encryption for production, ensure the keys are generated from a high quality random number source and do not share the same flash encryption key across multiple devices.** + +Pregenerating a Flash Encryption Key +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Flash encryption keys are 32 bytes of random data. You can generate a random key with espsecure.py:: + + espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin + +(The randomness of this data is only as good as the OS and it's Python installation's random data source.) + +Alternatively, if you're using :doc:`secure boot ` and have a secure boot signing key then you can generate a deterministic SHA-256 digest of the secure boot private signing key and use this as the flash encryption key:: + + espsecure.py digest_private-key --keyfile secure_boot_signing_key.pem my_flash_encryption_key.bin + +(The same 32 bytes is used as the secure boot digest key if you enable :ref:`reflashable mode` for secure boot.) + +Generating the flash encryption key from the secure boot signing key in this way means that you only need to store one key file. However this method is **not at all suitable** for production devices. + +Burning Flash Encryption Key +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once you have generated a flash encryption key, you need to burn it to the ESP32's efuse key block. **This must be done before first encrypted boot**, otherwise the ESP32 will generate a random key that software can't access or modify. + +To burn a key to the device (one time only):: + + espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin + +First Flash with pregenerated key +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After flashing the key, follow the same steps as for default :ref:`flash-encryption-initialisation` and flash a plaintext image for the first boot. The bootloader will enable flash encryption using the pre-burned key and encrypt all partitions. + +Reflashing with pregenerated key +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After encryption is enabled on first boot, reflashing an encrypted image requires an additional manual step. This is where we pre-encrypt the data that we wish to update in flash. + +Suppose that this is the normal command used to flash plaintext data:: + + esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash 0x10000 build/my-app.bin + +Binary app image ``build/my-app.bin`` is written to offset ``0x10000``. This file name and offset need to be used to encrypt the data, as follows:: + + espsecure.py encrypt_flash_data --keyfile my_flash_encryption_key.bin --address 0x10000 -o build/my-app-encrypted.bin build/my-app.bin + +This example command will encrypts ``my-app.bin`` using the supplied key, and produce an encrypted file ``my-app-encrypted.bin``. Be sure that the address argument matches the address where you plan to flash the binary. + +Then, flash the encrypted binary with esptool.py:: + + esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash 0x10000 build/my-app-encrypted.bin + +No further steps or efuse manipulation is necessary, because the data is already encrypted when we flash it. + +Disabling Flash Encryption +-------------------------- + +If you've accidentally enabled flash encryption for some reason, the next flash of plaintext data will soft-brick the ESP32 (the device will reboot continously, printing the error ``flash read err, 1000``). + +You can disable flash encryption again by writing :ref:`FLASH_CRYPT_CNT`: + +- First, run ``make menuconfig`` and uncheck "Enable flash encryption boot" under "Security Features". +- Exit menuconfig and save the new configuration. +- Run ``make menuconfig`` again and double-check you really disabled this option! *If this option is left enabled, the bootloader will immediately re-enable encryption when it boots*. +- Run ``make flash`` to build and flash a new bootloader and app, without flash encryption enabled. +- Run ``espefuse.py`` (in ``components/esptool_py/esptool``) to disable the :ref:`FLASH_CRYPT_CNT`):: + espefuse.py burn_efuse FLASH_CRYPT_CNT + +Reset the ESP32 and flash encryption should be disabled, the bootloader will boot as normal. + +.. _flash-encryption-limitations: + Limitations of Flash Encryption ------------------------------- Flash Encryption prevents plaintext readout of the encrypted flash, to protect firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption system: -- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device to burn with ``esp_efuse.py burn_key``, ensure they are generated from a quality random number source, kept secure, and never shared between devices. +- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device (see :ref:`pregenerated-flash-encryption-key`), ensure proper procedure is followed. - Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption. -- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every two 16 byte AES blocks. When both adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (ie to tell if two devices are probably running the same firmware version). +- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every pair of adjacent 16 byte AES blocks. When these adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (ie to tell if two devices are probably running the same firmware version). -- For the same reason, an attacker can always guess when two adjacent 16 byte blocks (32 byte aligned) contain identical content. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient). +- For the same reason, an attacker can always tell when a pair of adjacent 16 byte blocks (32 byte aligned) contain identical content. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient). -- Flash encryption alone may not prevent an attacker from modifying the firmware of the device. Always use flash encryption in combination with Secure Boot. +- Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from runningon the device, use flash encryption in combination with :doc:`Secure Boot `. +.. _flash-encryption-advanced-features: Flash Encryption Advanced Features ---------------------------------- +The following information is useful for advanced use of flash encryption: + Encrypted Partition Flag ^^^^^^^^^^^^^^^^^^^^^^^^ -In the `partition table` description CSV files, there is a field for flags. +Some partitions are encrypted by default. Otherwise, it is possible to mark any partition as requiring encryption: + +In the :doc:`partition table ` description CSV files, there is a field for flags. Usually left blank, if you write "encrypted" in this field then the partition will be marked as encrypted in the partition table, and data written here will be treated as encrypted (same as an app partition):: @@ -187,7 +292,7 @@ Usually left blank, if you write "encrypted" in this field then the partition wi factory, app, factory, 0x10000, 1M secret_data, 0x40, 0x01, 0x20000, 256K, encrypted -- None of the default partition formats have any encrypted data partitions. +- None of the default partition tables include any encrypted data partitions. - It is not necessary to mark "app" partitions as encrypted, they are always treated as encrypted. @@ -197,88 +302,70 @@ Usually left blank, if you write "encrypted" in this field then the partition wi - It is not possible to mark the ``nvs`` partition as encrypted. -Precalculated Flash Encryption Key -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -It is possible to pre-generate a flash encryption key on the host computer and burn it into the ESP32 efuse. This allows data to be per-encrypted on the host and flashed to the ESP32 without needing a plaintext flash update. - -This is useful for development, because it removes the 4 flash limit and allows reflashing with secure boot enabled. - -**IMPORTANT** This method is intended to assist with development only, not for production devices. If pre-generating flash encryption for production, ensure the keys are generated from a high quality random number source and do not share the same flash encryption key across multiple devices. - -Obtaining Flash Encryption Key -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Flash encryption keys are 32 bytes of random data. You can generate a random key with espsecure.py:: - - espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin - -(The randomness of this data is only as good as the OS and it's Python installation's random data source.) - -Alternatively, if you're using `secure boot` and have a secure boot signing key then you can generate a deterministic SHA-256 digest of the secure boot private key to use:: - - espsecure.py digest_private-key --keyfile secure_boot_signing_key.pem my_flash_encryption_key.bin - -The same key is used as the secure boot digest key if you enabled "Reflashable" mode for secure boot. - -This means you can always re-calculate the flash encryption key from the secure boot private signing key. This method is **not at all suitable** for production devices. - -Burning Flash Encryption Key -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Once you have generated a flash encryption key, you need to burn it to efuse on the device. This **must be done before first boot**, otherwise the ESP32 will generate a random key that software can't access. - -To burn a key to the device (possible one time only):: - - espefuse.py burn_key flash_encryption my_flash_encryption_key.bin - -First Flash -~~~~~~~~~~~ - -For the first flash, follow the same steps as for default `Flash Encryption Initialisation` and flash a plaintext image. The bootloader will enable flash encryption using the pre-burned key and encrypt all partitions. - -Reflashing -~~~~~~~~~~ - -To reflash an encrypted image requires an additional manual update step, to encrypt the data you wish to flash. - -Suppose that this is the normal flashing non-encrypted flashing step:: - - esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash -z 0x10000 build/my-app.bin - -The data needs to be pre-encrypted with knowledge of the address (0x10000) and the binary file name:: - - espsecure.py encrypt_flash_data --keyfile my_flash_encryption_key.bin --address 0x10000 -o build/my-app-encrypted.bin build/my-app.bin - -This step will encrypt ``my-app.bin`` using the supplied key, and produce an encrypted file ``my-app-encrypted.bin``. Be sure that the address argument matches the address where you plan to flash the binary. - -Then, flash the encrypted binary with esptool.py:: - - esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash -z 0x10000 build/my-app-encrypted.bin +.. _uart-bootloader-encryption: Enabling UART Bootloader Encryption/Decryption ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -By default, on first boot the flash encryption process will burn efuses ``DISABLE_DL_ENCRYPT``, ``DISABLE_DL_DECRYPT`` and ``DISABLE_DL_CACHE``. +By default, on first boot the flash encryption process will burn efuses ``DISABLE_DL_ENCRYPT``, ``DISABLE_DL_DECRYPT`` and ``DISABLE_DL_CACHE``: - ``DISABLE_DL_ENCRYPT`` disables the flash encryption operations when running in UART bootloader boot mode. -- ``DISABLE_DL_DECRYPT`` disables transparent flash decryption when running in UART bootloader mode, even if ``FLASH_CRYPT_CNT`` is set to enable it in normal operation. +- ``DISABLE_DL_DECRYPT`` disables transparent flash decryption when running in UART bootloader mode, even if :ref:`FLASH_CRYPT_CNT` is set to enable it in normal operation. - ``DISABLE_DL_CACHE`` disables the entire MMU flash cache when running in UART bootloader mode. -It is possible to burn only some of these efuses, and write-protect the rest (with unset value 0) before the first boot, in order to preserve them:: +It is possible to burn only some of these efuses, and write-protect the rest (with unset value 0) before the first boot, in order to preserve them. For example:: - espefuse.py burn_efuse DISABLE_DL_DECRYPT - espefuse.py write_protect_efuse DISABLE_DL_ENCRYPT + espefuse.py --port PORT burn_efuse DISABLE_DL_DECRYPT + espefuse.py --port PORT write_protect_efuse DISABLE_DL_ENCRYPT -(Note that all 3 of these efuses are disabled via one write protect bit, so write protecting one will write protect all of them.) +(Note that all 3 of these efuses are disabled via one write protect bit, so write protecting one will write protect all of them. For this reason, it's necessary to set any bits before write-protecting.) -Write protecting these efuses when they are unset (0) is not currently useful, as ``esptool.py`` does not support flash encryption functions. +**IMPORTANT**: Write protecting these efuses to keep them unset is not currently very useful, as ``esptool.py`` does not support writing or reading encrypted flash. + +**IMPORTANT**: If ``DISABLE_DL_DECRYPT`` is left unset (0) this effectively makes flash encryption useless, as an attacker with physical access can use UART bootloader mode (with custom stub code) to read out the flash contents. + +.. _setting-flash-crypt-config: + +Setting FLASH_CRYPT_CONFIG +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``FLASH_CRYPT_CONFIG`` efuse determines the number of bits in the flash encryption key which are "tweaked" with the block offset. See :ref:`flash-encryption-algorithm` for details. + +First boot of the bootloader always sets this value to the maximum `0xF`. + +It is possible to write these efuse manually, and write protect it before first boot in order to select different tweak values. This is not recommended. + +It is strongly recommended to never write protect ``FLASH_CRYPT_CONFIG`` when it the value is zero. If this efuse is set to zero, no bits in the flash encryption key are tweaked and the flash encryption algorithm is equivalent to AES ECB mode. -However, note that write protecting ``DISABLE_DL_DECRYPT`` when it is unset (0) effectively makes flash encryption useless, as an attacker with physical access can use UART bootloader mode to read out the flash. Technical Details ----------------- +The following sections provide some reference information about the operation of flash encryption. + +.. _FLASH_CRYPT_CNT: + +FLASH_CRYPT_CNT efuse +^^^^^^^^^^^^^^^^^^^^^ + +``FLASH_CRYPT_CNT`` is an 8-bit efuse field which controls flash encryption. Flash encryption enables or disables based on the number of bits in this efuse which are set to "1": + +- When an even number of bits (0,2,4,6,8) are set: Flash encryption is disabled, any encrypted data cannot be decrypted. + + - If the bootloader was built with "Enable flash encryption on boot" then it will see this situation and immediately re-encrypt the flash wherever it finds unencrypted data. Once done, it sets another bit in the efuse to '1' meaning an odd number of bits are now set. + + 1. On first plaintext boot, bit count has brand new value 0 and bootloader changes it to bit count 1 (value 0x01) following encryption. + 2. After next plaintext flash update, bit count is manually updated to 2 (value 0x03). After re-encrypting the bootloader changes efuse bit count to 3 (value 0x07). + 3. After next plaintext flash, bit count is manually updated to 4 (value 0x0F). After re-encrypting the bootloader changes efuse bit count to 5 (value 0x1F). + 4. After final plaintext flash, bit count is manually updated to 6 (value 0x3F). After re-encrypting the bootloader changes efuse bit count to 7 (value 0x7F). + +- When an odd number of bits (1,3,5,7) are set: Transparent reading of encrypted flash is enabled. + +- After all 8 bits are set (efuse value 0xFF): Transparent reading of encrypted flash is disabled, any encrypted data is permanently inaccessible. Bootloader will normally detect this condition and halt. To avoid use of this state to load unauthorised code, secure boot must be used or :ref:`FLASH_CRYPT_CNT` must be write-protected. + + +.. _flash-encryption-algorithm: + Flash Encryption Algorithm ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -288,31 +375,20 @@ Flash Encryption Algorithm - The main flash encryption key is stored in efuse (BLK2) and by default is protected from further writes or software readout. -- Each 32 byte block is encrypted with a unique key which is derived from this main flash encryption key XORed with the offset of this block in the flash (a "key tweak"). +- Each 32 byte block (two adjacent 16 byte AES blocks) is encrypted with a unique key. The key is derived from the main flash encryption key in efuse, XORed with the offset of this block in the flash (a "key tweak"). - The specific tweak depends on the setting of ``FLASH_CRYPT_CONFIG`` efuse. This is a 4 bit efuse, where each bit enables XORing of a particular range of the key bits: + - Bit 1, bits 0-66 of the key are XORed. - Bit 2, bits 67-131 of the key are XORed. - Bit 3, bits 132-194 of the key are XORed. - Bit 4, bits 195-256 of the key are XORed. -It is recommended that ``FLASH_CRYPT_CONFIG`` is always left to set the default value `0xF`, so that all key bits are XORed with the block offset. See `Setting FLASH_CRYPT_CONFIG` for details. + + It is recommended that ``FLASH_CRYPT_CONFIG`` is always left to set the default value `0xF`, so that all key bits are XORed with the block offset. See :ref:`setting-flash-crypt-config` for details. - The high 19 bits of the block offset (bit 5 to bit 23) are XORed with the main flash encryption key. This range is chosen for two reasons: the maximum flash size is 16MB (24 bits), and each block is 32 bytes so the least significant 5 bits are always zero. -- There is a particular mapping from each of the 19 block offset bits to the 256 bits of the flash encryption key, to determine which bit is XORed with which. See the variable _FLASH_ENCRYPTION_TWEAK_PATTERN in espsecure.py for a list of these. +- There is a particular mapping from each of the 19 block offset bits to the 256 bits of the flash encryption key, to determine which bit is XORed with which. See the variable ``_FLASH_ENCRYPTION_TWEAK_PATTERN`` in the espsecure.py source code for the complete mapping. -- For the full algorithm implemented in Python, see `_flash_encryption_operation()` in the espsecure.py source code. +- To see the full flash encryption algorithm implemented in Python, refer to the `_flash_encryption_operation()` function in the espsecure.py source code. -Setting FLASH_CRYPT_CONFIG -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The ``FLASH_CRYPT_CONFIG`` efuse determines the number of bits in the flash encryption key which are "tweaked" with the block offset. See `Flash Encryption Algorithm` for details. - -First boot of the bootloader always sets this value to the maximum `0xF`. - -It is possible to write these efuse manually, and write protect it before first boot in order to select different tweak values. This is not recommended. - -It is strongly recommended to never write protect ``FLASH_CRYPT_CONFIG`` when it the value is zero. If this efuse is set to zero, no bits in the flash encryption key are tweaked and the flash encryption algorithm is equivalent to AES ECB mode. - -.. _Secure Boot: secure-boot.rst -.. _partition table: ../partition-tables.rst diff --git a/docs/security/secure-boot.rst b/docs/security/secure-boot.rst index 3c247d4a46..f90141a5ea 100644 --- a/docs/security/secure-boot.rst +++ b/docs/security/secure-boot.rst @@ -3,7 +3,9 @@ Secure Boot Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset. -Secure Boot is separate from the `Flash Encryption` feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment. +Secure Boot is separate from the :doc:`Flash Encryption ` feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment. + +**IMPORTANT: Enabling secure boot limits your options for further updates of your ESP32. Make sure to read this document throughly and understand the implications of enabling secure boot.** Background ---------- @@ -19,7 +21,7 @@ Background Secure Boot Process Overview ---------------------------- -This is a high level overview of the secure boot process. Step by step instructions are supplied under `How To Enable Secure Boot`. Further in-depth details are supplied under `Technical Details`: +This is a high level overview of the secure boot process. Step by step instructions are supplied under :ref:`secure-boot-howto`. Further in-depth details are supplied under :ref:`secure-boot-technical-details`: 1. The options to enable secure boot are provided in the ``make menuconfig`` hierarchy, under "Secure Boot Configuration". @@ -34,7 +36,7 @@ This is a high level overview of the secure boot process. Step by step instructi - Depending on Secure Boot Configuration, efuses are burned to disable JTAG and the ROM BASIC interpreter (it is strongly recommended these options are turned on.) - Bootloader permanently enables secure boot by burning the ABS_DONE_0 efuse. The software bootloader then becomes protected (the chip will only boot a bootloader image if the digest matches.) -5. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see `Hardware Secure Boot Support`. +5. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see :ref:`secure-boot-hardware-support`. 6. When running in secure boot mode, the software bootloader uses the secure boot signing key (the public key of which is embedded in the bootloader itself, and therefore validated as part of the bootloader) to verify the signature appended to all subsequent partition tables and app images before they are booted. @@ -43,19 +45,20 @@ Keys The following keys are used by the secure boot process: -- "secure bootloader key" is a 256-bit AES key that is stored in Efuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, the user does not need to supply it (it is optionally possible to supply this key, see `Re-Flashable Software Bootloader`). The Efuse holding this key is read & write protected (preventing software access) before secure boot is enabled. +- "secure bootloader key" is a 256-bit AES key that is stored in Efuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, the user does not need to supply it (it is optionally possible to supply this key, see :ref:`secure-boot-reflashable`). The Efuse holding this key is read & write protected (preventing software access) before secure boot is enabled. -- "secure boot signing key" is a standard ECDSA public/private key pair (see `Image Signing Algorithm`) in PEM format. +- "secure boot signing key" is a standard ECDSA public/private key pair (see :ref:`secure-boot-image-signing-algorithm`) in PEM format. - The public key from this key pair (for signature verificaton but not signature creation) is compiled into the software bootloader and used to verify the second stage of booting (partition table, app image) before booting continues. The public key can be freely distributed, it does not need to be kept secret. - The private key from this key pair *must be securely kept private*, as anyone who has this key can authenticate to any bootloader that is configured with secure boot and the matching public key. +.. _secure-boot-howto: How To Enable Secure Boot ------------------------- -1. Run ``make menuconfig``, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see `Re-Flashable Software Bootloader`.) +1. Run ``make menuconfig``, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see :ref:`secure-boot-reflashable`.) 2. Select a name for the secure boot signing key. This option will appear after secure boot is enabled. The file can be anywhere on your system. A relative path will be evaluated from the project directory. The file does not need to exist yet. @@ -65,22 +68,26 @@ How To Enable Secure Boot **IMPORTANT** A signing key generated this way will use the best random number source available to the OS and its Python installation (`/dev/urandom` on OSX/Linux and `CryptGenRandom()` on Windows). If this random number source is weak, then the private key will be weak. - **IMPORTANT** For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See `Generating Secure Boot Signing Key` for more details. + **IMPORTANT** For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See :ref:`secure-boot-generate-key` for more details. -5. Run ``make bootloader`` to build a secure boot enabled bootloader. The output of `make` will include a prompt for a flashing command, using `esptool.py write_flash`. +5. Run ``make bootloader`` to build a secure boot enabled bootloader. The output of ``make`` will include a prompt for a flashing command, using ``esptool.py write_flash``. + +.. _secure-boot-resume-normal-flashing: 6. When you're ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by make) and then wait for flashing to complete. **Remember this is a one time flash, you can't change the bootloader after this!**. -7. Run `make flash` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4. +7. Run ``make flash`` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4. - *NOTE*: `make flash` doesn't flash the bootloader if secure boot is enabled. + *NOTE*: ``make flash`` doesn't flash the bootloader if secure boot is enabled. 8. Reset the ESP32 and it will boot the software bootloader you flashed. The software bootloader will enable secure boot on the chip, and then it verifies the app image signature and boots the app. You should watch the serial console output from the ESP32 to verify that secure boot is enabled and no errors have occured due to the build configuration. -*NOTE* Secure boot won't be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured. +**NOTE** Secure boot won't be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured. 9. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed (using the secure bootloader key) and then the software bootloader will verify the signed partition table and app image (using the public key portion of the secure boot signing key). +.. _secure-boot-reflashable: + Re-Flashable Software Bootloader -------------------------------- @@ -90,7 +97,7 @@ However, an alternative mode "Secure Boot: Reflashable" is also available. This In the esp-idf build process, this 256-bit key file is derived from the app signing key generated during the generate_signing_key step above. The private key's SHA-256 digest is used as the 256-bit secure bootloader key. This is a convenience so you only need to generate/protect a single private key. -*NOTE*: Although it's possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The "One-Time Flash" option is recommended for production environments. +**NOTE**: Although it's possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The "One-Time Flash" option is recommended for production environments. To enable a reflashable bootloader: @@ -100,7 +107,9 @@ To enable a reflashable bootloader: 3. Run ``make bootloader``. A 256-bit key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed - the first set of steps includes an ``espefuse.py burn_key`` command which is used to write the bootloader key to efuse. (Flashing this key is a one-time-only process.) The second set of steps can be used to reflash the bootloader with a pre-calculated digest (generated during the build process). -4. Resume from `Step 6` of the one-time process, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration. +4. Resume from :ref:`Step 6 of the one-time flashing process `, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration. + +.. _secure-boot-generate-key: Generating Secure Boot Signing Key ---------------------------------- @@ -134,7 +143,7 @@ After the app image and partition table are built, the build system will print s espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY BINARY_FILE -The above command appends the image signature to the existing binary. You can use the --output argument to place the binary with signature appended into a separate file:: +The above command appends the image signature to the existing binary. You can use the `--output` argument to write the signed binary to a separate file:: espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE @@ -145,16 +154,21 @@ Secure Boot Best Practices * Keep the signing key private at all times. A leak of this key will compromise the secure boot system. * Do not allow any third party to observe any aspects of the key generation or signing process using espsecure.py. Both processes are vulnerable to timing or other side-channel attacks. * Enable all secure boot options in the Secure Boot Configuration. These include flash encryption, disabling of JTAG, disabling BASIC ROM interpeter, and disabling the UART bootloader encrypted flash access. +* Use secure boot in combination with :doc:`flash encryption` to prevent local readout of the flash contents. + +.. _secure-boot-technical-details: Technical Details ----------------- -The following sections contain low-level descriptions of various technical functions: +The following sections contain low-level reference descriptions of various secure boot elements: -Hardware Secure Boot Support +.. _secure-boot-hardware-support: + +Secure Boot Hardware Support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The Secure Boot support hardware can perform three basic operations: +The first stage of secure boot verification (checking the software bootloader) is done via hardware. The ESP32's Secure Boot support hardware can perform three basic operations: 1. Generate a random sequence of bytes from a hardware random number generator. @@ -167,7 +181,7 @@ Secure Bootloader Digest Algorithm Starting with an "image" of binary data as input, this algorithm generates a digest as output. The digest is sometimes referred to as an "abstract" in hardware documentation. -For a Python version of this algorithm, see the `espsecure.py` tool in the components/esptool_py directory. +For a Python version of this algorithm, see the ``espsecure.py`` tool in the components/esptool_py directory (specifically, the ``digest_secure_bootloader`` command). Items marked with (^) are to fulfill hardware restrictions, as opposed to cryptographic restrictions. @@ -183,23 +197,27 @@ Items marked with (^) are to fulfill hardware restrictions, as opposed to crypto Output digest is 192 bytes of data: The 128 byte IV, followed by the 64 byte SHA-512 digest. +.. _secure-boot-image-signing-algorithm: + Image Signing Algorithm ~~~~~~~~~~~~~~~~~~~~~~~ -Deterministic ECDSA as specified by `RFC6979`. +Deterministic ECDSA as specified by `RFC 6979 `_. - Curve is NIST256p (openssl calls this curve "prime256v1", it is also sometimes called secp256r1). - Hash function is SHA256. - Key format used for storage is PEM. + - In the bootloader, the public key (for signature verification) is flashed as 64 raw bytes. + - Image signature is 68 bytes - a 4 byte version word (currently zero), followed by a 64 bytes of signature data. These 68 bytes are appended to an app image or partition table data. Manual Commands ~~~~~~~~~~~~~~~ -Secure boot is integrated into the esp-idf build system, so `make` will automatically sign an app image if secure boot is enabled. `make bootloader` will produce a bootloader digest if menuconfig is configured for it. +Secure boot is integrated into the esp-idf build system, so ``make`` will automatically sign an app image if secure boot is enabled. ``make bootloader`` will produce a bootloader digest if menuconfig is configured for it. -However, it is possible to use the `espsecure.py` tool to make standalone signatures and digests. +However, it is possible to use the ``espsecure.py`` tool to make standalone signatures and digests. To sign a binary image:: @@ -215,5 +233,3 @@ Keyfile is the 32 byte raw secure boot key for the device. To flash this digest esptool.py write_flash 0x0 bootloader-digest.bin -.. _RFC6979: https://tools.ietf.org/html/rfc6979 -.. _Flash Encryption: flash-encryption.rst diff --git a/docs/ulp.rst b/docs/ulp.rst new file mode 100644 index 0000000000..4ee6ed7a2f --- /dev/null +++ b/docs/ulp.rst @@ -0,0 +1 @@ +.. include:: ../components/ulp/README.rst diff --git a/docs/unit-tests.rst b/docs/unit-tests.rst new file mode 100644 index 0000000000..a32533755e --- /dev/null +++ b/docs/unit-tests.rst @@ -0,0 +1,68 @@ +Unit Testing in ESP32 +===================== + +ESP-IDF comes with a unit test app based on Unity - unit test framework. Unit tests are integrated in the ESP-IDF repository and are placed in ``test`` subdirectory of each component respectively. + +Adding unit tests +----------------- + +Unit tests are added in the ``test`` subdirectory of the respective component. +Tests are added in C files, a single C file can include multiple test cases. +Test files start with the word "test". + +The test file should include unity.h and the header for the C module to be tested. + +Tests are added in a function in the C file as follows:: + + TEST_CASE("test name", "[module name]" + { + // Add test here + } + +First argument is a descriptive name for the test, second argument is an identifier in square brackets. +Identifiers are used to group related test, or tests with specific properties. + +There is no need to add a main function with ``UNITY_BEGIN()`` and ``​UNITY_END()`` in each test case. +``unity_platform.c`` will run ``UNITY_BEGIN()``, run the tests cases, and then call ``​UNITY_END()``. + +Each `test` subdirectory needs to include component.mk file with at least the following line of code:: + + COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive + +See http://www.throwtheswitch.org/unity for more information about writing tests in Unity. + +Building unit test app +---------------------- + +Follow the setup instructions in the top-level esp-idf README. +Make sure that IDF_PATH environment variable is set to point to the path of esp-idf top-level directory. + +Change into tools/unit-test-app directory to configure and build it: + +* `make menuconfig` - configure unit test app. + +* `make TESTS_ALL=1` - build unit test app with tests for each component having tests in the ``test`` subdirectory. +* `make TEST_COMPONENTS='xxx'` - build unit test app with tests for specific components. + +When the build finishes, it will print instructions for flashing the chip. You can simply run ``make flash`` to flash all build output. + +You can also run ``make flash TESTS_ALL=1`` or ``make TEST_COMPONENTS='xxx'`` to build and flash. Everything needed will be rebuilt automatically before flashing. + +Use menuconfig to set the serial port for flashing. + +Running unit tests +------------------ + +After flashing reset the ESP32 and it will boot the unit test app. + +Unit test app prints a test menu with all available tests. + +Test cases can be run by inputting one of the following: + +- Test case name in quotation marks to run a single test case + +- Test case index to run a single test case + +- Module name in square brackets to run all test cases for a specific module + +- An asterisk to run all test cases diff --git a/docs/windows-setup.rst b/docs/windows-setup.rst index 00205fb78b..996eacee56 100644 --- a/docs/windows-setup.rst +++ b/docs/windows-setup.rst @@ -23,7 +23,7 @@ As an alternative to getting a pre-prepared environment, you can set up the envi * Run through the installer steps, and accept the "Run MSYS2 now" option at the end. A window will open with a MSYS2 terminal. -* The ESP-IDF repository on github contains a script in the tools directory titled ``windows_install_prerequisites.sh``. If you haven't downloaded the ESP-IDF yet, that's OK - you can just `download that one file in Raw format from here `_. Save it somewhere on your computer. +* The ESP-IDF repository on github contains a script in the tools directory titled ``windows_install_prerequisites.sh``. If you haven't downloaded the ESP-IDF yet, that's OK - you can just download that one file in Raw format from here: :idf_raw:`tools/windows/windows_install_prerequisites.sh`. Save it somewhere on your computer. * Type the path to the shell script into the MSYS2 terminal window. You can type it as a normal Windows path, but use forward-slashes instead of back-slashes. ie: ``C:/Users/myuser/Downloads/windows_install_prerequisites.sh``. You can read the script beforehand to check what it does. diff --git a/examples/09_a2dp/main/demo_main.c b/examples/09_a2dp/main/demo_main.c index 9a4288a754..6cc1f0cb18 100755 --- a/examples/09_a2dp/main/demo_main.c +++ b/examples/09_a2dp/main/demo_main.c @@ -21,5 +21,9 @@ void app_main() // printf("Free memory: %d bytes\n", system_get_free_heap_size()); // EspAudio_Init(); esp_bt_controller_init(); + + if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) { + return; + } bt_app_task_start_up(); } diff --git a/examples/14_gatt_server/README.rst b/examples/14_gatt_server/README.rst deleted file mode 100644 index 85d860f285..0000000000 --- a/examples/14_gatt_server/README.rst +++ /dev/null @@ -1,5 +0,0 @@ -ESP-IDF GATT SERVER demo -======================== - -This is the demo for user to use ESP_APIs to create a GATT Server. - diff --git a/examples/bluetooth/README.md b/examples/bluetooth/README.md new file mode 100644 index 0000000000..3d60a59162 --- /dev/null +++ b/examples/bluetooth/README.md @@ -0,0 +1,5 @@ +# Bluetooth Examples + +Note: To use examples in this directory, you need to have Bluetooth enabled in configuration. Run `make menuconfig`, go to `Component config` and verify if you see `[*] Bluetooth`. If not - enable it and save. + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/05_ble_adv/Makefile b/examples/bluetooth/ble_adv/Makefile similarity index 100% rename from examples/05_ble_adv/Makefile rename to examples/bluetooth/ble_adv/Makefile diff --git a/examples/05_ble_adv/README.rst b/examples/bluetooth/ble_adv/README.rst similarity index 100% rename from examples/05_ble_adv/README.rst rename to examples/bluetooth/ble_adv/README.rst diff --git a/examples/05_ble_adv/main/app_bt.c b/examples/bluetooth/ble_adv/main/app_bt.c similarity index 98% rename from examples/05_ble_adv/main/app_bt.c rename to examples/bluetooth/ble_adv/main/app_bt.c index f0780c950c..67ab2c8fe0 100644 --- a/examples/05_ble_adv/main/app_bt.c +++ b/examples/bluetooth/ble_adv/main/app_bt.c @@ -215,6 +215,11 @@ void bleAdvtTask(void *pvParameters) void app_main() { esp_bt_controller_init(); + + if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) { + return; + } + xTaskCreatePinnedToCore(&bleAdvtTask, "bleAdvtTask", 2048, NULL, 5, NULL, 0); } diff --git a/examples/02_blink/main/component.mk b/examples/bluetooth/ble_adv/main/component.mk similarity index 100% rename from examples/02_blink/main/component.mk rename to examples/bluetooth/ble_adv/main/component.mk diff --git a/examples/05_ble_adv/sdkconfig.defaults b/examples/bluetooth/ble_adv/sdkconfig.defaults similarity index 100% rename from examples/05_ble_adv/sdkconfig.defaults rename to examples/bluetooth/ble_adv/sdkconfig.defaults diff --git a/examples/12_blufi/Makefile b/examples/bluetooth/blufi/Makefile similarity index 100% rename from examples/12_blufi/Makefile rename to examples/bluetooth/blufi/Makefile diff --git a/examples/12_blufi/README.rst b/examples/bluetooth/blufi/README.rst similarity index 100% rename from examples/12_blufi/README.rst rename to examples/bluetooth/blufi/README.rst diff --git a/examples/12_blufi/main/blufi_demo.h b/examples/bluetooth/blufi/main/blufi_demo.h similarity index 100% rename from examples/12_blufi/main/blufi_demo.h rename to examples/bluetooth/blufi/main/blufi_demo.h diff --git a/examples/12_blufi/main/blufi_main.c b/examples/bluetooth/blufi/main/blufi_main.c similarity index 98% rename from examples/12_blufi/main/blufi_main.c rename to examples/bluetooth/blufi/main/blufi_main.c index a95db66eb5..b46ffb4648 100644 --- a/examples/12_blufi/main/blufi_main.c +++ b/examples/bluetooth/blufi/main/blufi_main.c @@ -317,6 +317,12 @@ void app_main() esp_bt_controller_init(); + ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM); + if (ret) { + BLUFI_ERROR("%s enable bt controller failed\n", __func__); + return; + } + ret = esp_bluedroid_init(); if (ret) { BLUFI_ERROR("%s init bluedroid failed\n", __func__); diff --git a/examples/12_blufi/main/blufi_security.c b/examples/bluetooth/blufi/main/blufi_security.c similarity index 100% rename from examples/12_blufi/main/blufi_security.c rename to examples/bluetooth/blufi/main/blufi_security.c diff --git a/examples/12_blufi/main/component.mk b/examples/bluetooth/blufi/main/component.mk similarity index 100% rename from examples/12_blufi/main/component.mk rename to examples/bluetooth/blufi/main/component.mk diff --git a/examples/12_blufi/sdkconfig.defaults b/examples/bluetooth/blufi/sdkconfig.defaults similarity index 100% rename from examples/12_blufi/sdkconfig.defaults rename to examples/bluetooth/blufi/sdkconfig.defaults diff --git a/examples/15_gatt_client/Makefile b/examples/bluetooth/gatt_client/Makefile similarity index 100% rename from examples/15_gatt_client/Makefile rename to examples/bluetooth/gatt_client/Makefile diff --git a/examples/15_gatt_client/README.rst b/examples/bluetooth/gatt_client/README.rst similarity index 100% rename from examples/15_gatt_client/README.rst rename to examples/bluetooth/gatt_client/README.rst diff --git a/examples/15_gatt_client/main/component.mk b/examples/bluetooth/gatt_client/main/component.mk similarity index 100% rename from examples/15_gatt_client/main/component.mk rename to examples/bluetooth/gatt_client/main/component.mk diff --git a/examples/15_gatt_client/main/gattc_demo.c b/examples/bluetooth/gatt_client/main/gattc_demo.c similarity index 99% rename from examples/15_gatt_client/main/gattc_demo.c rename to examples/bluetooth/gatt_client/main/gattc_demo.c index e6ee867293..4a2fa0051d 100644 --- a/examples/15_gatt_client/main/gattc_demo.c +++ b/examples/bluetooth/gatt_client/main/gattc_demo.c @@ -397,6 +397,8 @@ void gattc_client_test(void) void app_main() { esp_bt_controller_init(); + esp_bt_controller_enable(ESP_BT_MODE_BTDM); + gattc_client_test(); } diff --git a/examples/14_gatt_server/sdkconfig.defaults b/examples/bluetooth/gatt_client/sdkconfig.defaults similarity index 100% rename from examples/14_gatt_server/sdkconfig.defaults rename to examples/bluetooth/gatt_client/sdkconfig.defaults diff --git a/examples/14_gatt_server/Makefile b/examples/bluetooth/gatt_server/Makefile similarity index 100% rename from examples/14_gatt_server/Makefile rename to examples/bluetooth/gatt_server/Makefile diff --git a/examples/bluetooth/gatt_server/README.rst b/examples/bluetooth/gatt_server/README.rst new file mode 100644 index 0000000000..bbfd76626c --- /dev/null +++ b/examples/bluetooth/gatt_server/README.rst @@ -0,0 +1,20 @@ +ESP-IDF GATT SERVER demo +======================== + +This is the demo for user to use ESP_APIs to create a GATT Server. + +Options choose step: + 1. make menuconfig. + 2. enter menuconfig "Component config". + 3. enter menuconfig "Example 'GATT SERVER' Config". + 4. choose your options. + +UPDATE NOTE +=========== + +2017-01-19: + 1. Use New APIs to set raw advertising data and raw scan response data. + 2. Could use macro CONFIG_SET_RAW_ADV_DATA (should use menuconfig) to config use raw advertising/scan_response + or use structure do automatically config. The macro CONFIG_SET_RAW_ADV will effect both advertising data + and scan_response data. + diff --git a/examples/bluetooth/gatt_server/main/Kconfig b/examples/bluetooth/gatt_server/main/Kconfig new file mode 100644 index 0000000000..7f01d57447 --- /dev/null +++ b/examples/bluetooth/gatt_server/main/Kconfig @@ -0,0 +1,12 @@ +menu "Example 'GATT SERVER' Config" + +config SET_RAW_ADV_DATA + bool "Use raw data for advertising packets and scan response data" + help + If this config item is set, raw binary data will be used to generate advertising & scan response data. + This option uses the esp_ble_gap_config_adv_data_raw() and esp_ble_gap_config_scan_rsp_data_raw() functions. + + If this config item is unset, advertising & scan response data is provided via a higher-level esp_ble_adv_data_t structure. + The lower layer will generate the BLE packets. This option has higher overhead at runtime. + +endmenu diff --git a/examples/14_gatt_server/main/component.mk b/examples/bluetooth/gatt_server/main/component.mk similarity index 100% rename from examples/14_gatt_server/main/component.mk rename to examples/bluetooth/gatt_server/main/component.mk diff --git a/examples/14_gatt_server/main/gatts_demo.c b/examples/bluetooth/gatt_server/main/gatts_demo.c similarity index 86% rename from examples/14_gatt_server/main/gatts_demo.c rename to examples/bluetooth/gatt_server/main/gatts_demo.c index 98feaa2240..acbf9195a0 100644 --- a/examples/14_gatt_server/main/gatts_demo.c +++ b/examples/bluetooth/gatt_server/main/gatts_demo.c @@ -30,6 +30,8 @@ #include "esp_bt_main.h" #include "esp_bt_main.h" +#include "sdkconfig.h" + #define GATTS_TAG "GATTS_DEMO" ///Declare the static function @@ -49,18 +51,26 @@ static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_i #define TEST_DEVICE_NAME "ESP_GATTS_DEMO" #define TEST_MANUFACTURER_DATA_LEN 17 -#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40 - -uint8_t char1_str[] ={0x11,0x22,0x33}; +#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40 +uint8_t char1_str[] = {0x11,0x22,0x33}; esp_attr_value_t gatts_demo_char1_val = { - .attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX, - .attr_len = sizeof(char1_str), - .attr_value = char1_str, + .attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX, + .attr_len = sizeof(char1_str), + .attr_value = char1_str, }; - +#ifdef CONFIG_SET_RAW_ADV_DATA +static uint8_t raw_adv_data[] = { + 0x02, 0x01, 0x06, 0x0f, 0x09, 0x45, 0x53, 0x50, 0x5f, 0x47, 0x41, 0x54, 0x54, 0x53, 0x5f, 0x44, + 0x45, 0x4d, 0x4f, 0x02, 0x0a, 0xeb, 0x03, 0x03, 0xab, 0xcd +}; +static uint8_t raw_scan_rsp_data[] = { + 0x02, 0x01, 0x06, 0x0f, 0x09, 0x45, 0x53, 0x50, 0x5f, 0x47, 0x41, 0x54, 0x54, 0x53, 0x5f, 0x44, + 0x45, 0x4d, 0x4f, 0x02, 0x0a, 0xeb, 0x03, 0x03, 0xab, 0xcd +}; +#else static uint8_t test_service_uuid128[32] = { /* LSB <--------------------------------------------------------------------------------> MSB */ //first uuid, 16bit, [12],[13] is the value @@ -85,6 +95,7 @@ static esp_ble_adv_data_t test_adv_data = { .p_service_uuid = test_service_uuid128, .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), }; +#endif /* CONFIG_SET_RAW_ADV_DATA */ static esp_ble_adv_params_t test_adv_params = { .adv_int_min = 0x20, @@ -134,6 +145,12 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&test_adv_params); break; + case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: + esp_ble_gap_start_advertising(&test_adv_params); + break; + case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: + esp_ble_gap_start_advertising(&test_adv_params); + break; default: break; } @@ -149,8 +166,12 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A; esp_ble_gap_set_device_name(TEST_DEVICE_NAME); +#ifdef CONFIG_SET_RAW_ADV_DATA + esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data)); + esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data)); +#else esp_ble_gap_config_adv_data(&test_adv_data); - +#endif esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A); break; case ESP_GATTS_READ_EVT: { @@ -194,7 +215,7 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i case ESP_GATTS_ADD_INCL_SRVC_EVT: break; case ESP_GATTS_ADD_CHAR_EVT: { - uint16_t length = 0; + uint16_t length = 0; const uint8_t *prf_char; ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", @@ -233,6 +254,8 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id; break; case ESP_GATTS_DISCONNECT_EVT: + esp_ble_gap_start_advertising(&test_adv_params); + break; case ESP_GATTS_OPEN_EVT: case ESP_GATTS_CANCEL_OPEN_EVT: case ESP_GATTS_CLOSE_EVT: @@ -247,15 +270,12 @@ static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_i switch (event) { case ESP_GATTS_REG_EVT: ESP_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); - gl_profile_tab[PROFILE_A_APP_ID].service_id.is_primary = true; - gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00; - gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; - gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_B; + gl_profile_tab[PROFILE_B_APP_ID].service_id.is_primary = true; + gl_profile_tab[PROFILE_B_APP_ID].service_id.id.inst_id = 0x00; + gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; + gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_B; - esp_ble_gap_set_device_name(TEST_DEVICE_NAME); - esp_ble_gap_config_adv_data(&test_adv_data); - - esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_B); + esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_B_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_B); break; case ESP_GATTS_READ_EVT: { ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); @@ -284,13 +304,13 @@ static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_i break; case ESP_GATTS_CREATE_EVT: ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); - gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle; - gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16; - gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_B; + gl_profile_tab[PROFILE_B_APP_ID].service_handle = param->create.service_handle; + gl_profile_tab[PROFILE_B_APP_ID].char_uuid.len = ESP_UUID_LEN_16; + gl_profile_tab[PROFILE_B_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_B; - esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle); + esp_ble_gatts_start_service(gl_profile_tab[PROFILE_B_APP_ID].service_handle); - esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid, + esp_ble_gatts_add_char(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].char_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, NULL, NULL); @@ -301,10 +321,10 @@ static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_i ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); - gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle; - gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; - gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; - esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid, + gl_profile_tab[PROFILE_B_APP_ID].char_handle = param->add_char.attr_handle; + gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; + gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; + esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].descr_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL); break; @@ -326,7 +346,7 @@ static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_i param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5], param->connect.is_connected); - gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id; + gl_profile_tab[PROFILE_B_APP_ID].conn_id = param->connect.conn_id; break; case ESP_GATTS_DISCONNECT_EVT: case ESP_GATTS_OPEN_EVT: @@ -374,6 +394,11 @@ void app_main() esp_bt_controller_init(); + ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM); + if (ret) { + ESP_LOGE(GATTS_TAG, "%s enable controller failed\n", __func__); + return; + } ret = esp_bluedroid_init(); if (ret) { ESP_LOGE(GATTS_TAG, "%s init bluetooth failed\n", __func__); diff --git a/examples/15_gatt_client/sdkconfig.defaults b/examples/bluetooth/gatt_server/sdkconfig.defaults similarity index 100% rename from examples/15_gatt_client/sdkconfig.defaults rename to examples/bluetooth/gatt_server/sdkconfig.defaults diff --git a/examples/33_gatt_server_service_table/Makefile b/examples/bluetooth/gatt_server_service_table/Makefile similarity index 100% rename from examples/33_gatt_server_service_table/Makefile rename to examples/bluetooth/gatt_server_service_table/Makefile diff --git a/examples/33_gatt_server_service_table/README.rst b/examples/bluetooth/gatt_server_service_table/README.rst similarity index 100% rename from examples/33_gatt_server_service_table/README.rst rename to examples/bluetooth/gatt_server_service_table/README.rst diff --git a/examples/33_gatt_server_service_table/main/component.mk b/examples/bluetooth/gatt_server_service_table/main/component.mk similarity index 100% rename from examples/33_gatt_server_service_table/main/component.mk rename to examples/bluetooth/gatt_server_service_table/main/component.mk diff --git a/examples/33_gatt_server_service_table/main/gatts_table_creat_demo.c b/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c similarity index 91% rename from examples/33_gatt_server_service_table/main/gatts_table_creat_demo.c rename to examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c index 024362c5b7..71baf1842c 100644 --- a/examples/33_gatt_server_service_table/main/gatts_table_creat_demo.c +++ b/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c @@ -29,6 +29,7 @@ #include "esp_bt_main.h" #include "gatts_table_creat_demo.h" +#define GATTS_TABLE_TAG "GATTS_TABLE_DEMO" #define HEART_PROFILE_NUM 1 #define HEART_PROFILE_APP_IDX 0 @@ -196,7 +197,7 @@ static const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] = static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { - LOG_ERROR("GAP_EVT, event %d\n", event); + ESP_LOGE(GATTS_TABLE_TAG, "GAP_EVT, event %d\n", event); switch (event) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: @@ -210,15 +211,15 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { - LOG_ERROR("event = %x\n",event); + ESP_LOGE(GATTS_TABLE_TAG, "event = %x\n",event); switch (event) { case ESP_GATTS_REG_EVT: - LOG_INFO("%s %d\n", __func__, __LINE__); + ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__); esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME); - LOG_INFO("%s %d\n", __func__, __LINE__); + ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__); esp_ble_gap_config_adv_data(&heart_rate_adv_config); - LOG_INFO("%s %d\n", __func__, __LINE__); + ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__); esp_ble_gatts_create_attr_tab(heart_rate_gatt_db, gatts_if, HRS_IDX_NB, HEART_RATE_SVC_INST_ID); break; @@ -256,7 +257,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, case ESP_GATTS_CONGEST_EVT: break; case ESP_GATTS_CREAT_ATTR_TAB_EVT:{ - LOG_ERROR("The number handle =%x\n",param->add_attr_tab.num_handle); + ESP_LOGE(GATTS_TABLE_TAG, "The number handle =%x\n",param->add_attr_tab.num_handle); if(param->add_attr_tab.num_handle == HRS_IDX_NB){ memcpy(heart_rate_handle_table, param->add_attr_tab.handles, sizeof(heart_rate_handle_table)); @@ -275,14 +276,14 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { - LOG_INFO("EVT %d, gatts if %d\n", event, gatts_if); + ESP_LOGI(GATTS_TABLE_TAG, "EVT %d, gatts if %d\n", event, gatts_if); /* If event is register event, store the gatts_if for each profile */ if (event == ESP_GATTS_REG_EVT) { if (param->reg.status == ESP_GATT_OK) { heart_rate_profile_tab[HEART_PROFILE_APP_IDX].gatts_if = gatts_if; } else { - LOG_INFO("Reg app failed, app_id %04x, status %d\n", + ESP_LOGI(GATTS_TABLE_TAG, "Reg app failed, app_id %04x, status %d\n", param->reg.app_id, param->reg.status); return; @@ -307,15 +308,22 @@ void app_main() esp_err_t ret; esp_bt_controller_init(); - LOG_INFO("%s init bluetooth\n", __func__); + + ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM); + if (ret) { + ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed\n", __func__); + return; + } + + ESP_LOGI(GATTS_TABLE_TAG, "%s init bluetooth\n", __func__); ret = esp_bluedroid_init(); if (ret) { - LOG_ERROR("%s init bluetooth failed\n", __func__); + ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed\n", __func__); return; } ret = esp_bluedroid_enable(); if (ret) { - LOG_ERROR("%s enable bluetooth failed\n", __func__); + ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed\n", __func__); return; } diff --git a/examples/33_gatt_server_service_table/main/gatts_table_creat_demo.h b/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.h similarity index 100% rename from examples/33_gatt_server_service_table/main/gatts_table_creat_demo.h rename to examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.h diff --git a/examples/33_gatt_server_service_table/sdkconfig.defaults b/examples/bluetooth/gatt_server_service_table/sdkconfig.defaults similarity index 100% rename from examples/33_gatt_server_service_table/sdkconfig.defaults rename to examples/bluetooth/gatt_server_service_table/sdkconfig.defaults diff --git a/examples/ethernet/README.md b/examples/ethernet/README.md new file mode 100644 index 0000000000..1b9ee845bb --- /dev/null +++ b/examples/ethernet/README.md @@ -0,0 +1,3 @@ +# Ethernet Examples + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/17_ethernet/Makefile b/examples/ethernet/ethernet/Makefile similarity index 100% rename from examples/17_ethernet/Makefile rename to examples/ethernet/ethernet/Makefile diff --git a/examples/17_ethernet/README.md b/examples/ethernet/ethernet/README.md similarity index 100% rename from examples/17_ethernet/README.md rename to examples/ethernet/ethernet/README.md diff --git a/examples/03_http_request/main/component.mk b/examples/ethernet/ethernet/main/component.mk similarity index 100% rename from examples/03_http_request/main/component.mk rename to examples/ethernet/ethernet/main/component.mk diff --git a/examples/17_ethernet/main/ethernet_main.c b/examples/ethernet/ethernet/main/ethernet_main.c similarity index 88% rename from examples/17_ethernet/main/ethernet_main.c rename to examples/ethernet/ethernet/main/ethernet_main.c index 57c6f97357..6419c41843 100644 --- a/examples/17_ethernet/main/ethernet_main.c +++ b/examples/ethernet/ethernet/main/ethernet_main.c @@ -37,6 +37,9 @@ static const char *TAG = "eth_demo"; #define DEFAULT_PHY_CONFIG (AUTO_MDIX_ENABLE|AUTO_NEGOTIATION_ENABLE|AN_1|AN_0|LED_CFG) +#define PIN_PHY_POWER 17 +#define PIN_SMI_MDC 23 +#define PIN_SMI_MDIO 18 void phy_tlk110_check_phy_init(void) { @@ -87,6 +90,17 @@ void phy_enable_flow_ctrl(void) esp_eth_smi_write(AUTO_NEG_ADVERTISEMENT_REG,data|ASM_DIR|PAUSE); } +void phy_tlk110_power_enable(bool enable) +{ + gpio_pad_select_gpio(PIN_PHY_POWER); + gpio_set_direction(PIN_PHY_POWER,GPIO_MODE_OUTPUT); + if(enable == true) { + gpio_set_level(PIN_PHY_POWER, 1); + } else { + gpio_set_level(PIN_PHY_POWER, 0); + } +} + void phy_tlk110_init(void) { esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET); @@ -117,11 +131,11 @@ void eth_gpio_config_rmii(void) //rmii clk ,can not change gpio_set_direction(0, GPIO_MODE_INPUT); - //mdc to gpio4 - gpio_matrix_out(4, EMAC_MDC_O_IDX, 0, 0); - //mdio to gpio2 - gpio_matrix_out(2, EMAC_MDO_O_IDX, 0, 0); - gpio_matrix_in(2, EMAC_MDI_I_IDX, 0); + //mdc to gpio23 + gpio_matrix_out(PIN_SMI_MDC, EMAC_MDC_O_IDX, 0, 0); + //mdio to gpio18 + gpio_matrix_out(PIN_SMI_MDIO, EMAC_MDO_O_IDX, 0, 0); + gpio_matrix_in(PIN_SMI_MDIO, EMAC_MDI_I_IDX, 0); } void eth_task(void *pvParameter) @@ -163,6 +177,7 @@ void app_main() //Only FULLDUPLEX mode support flow ctrl now! config.flow_ctrl_enable = true; config.phy_get_partner_pause_enable = phy_tlk110_get_partner_pause_enable; + config.phy_power_enable = phy_tlk110_power_enable; ret = esp_eth_init(&config); diff --git a/examples/17_ethernet/main/tlk110_phy.h b/examples/ethernet/ethernet/main/tlk110_phy.h similarity index 100% rename from examples/17_ethernet/main/tlk110_phy.h rename to examples/ethernet/ethernet/main/tlk110_phy.h diff --git a/examples/get-started/README.md b/examples/get-started/README.md new file mode 100644 index 0000000000..8a6792e718 --- /dev/null +++ b/examples/get-started/README.md @@ -0,0 +1,5 @@ +# Get Started Examples + +Simple code to get started with ESP32 and ESP-IDF. + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/02_blink/Makefile b/examples/get-started/blink/Makefile similarity index 100% rename from examples/02_blink/Makefile rename to examples/get-started/blink/Makefile diff --git a/examples/02_blink/README.md b/examples/get-started/blink/README.md similarity index 100% rename from examples/02_blink/README.md rename to examples/get-started/blink/README.md diff --git a/examples/02_blink/main/Kconfig.projbuild b/examples/get-started/blink/main/Kconfig.projbuild similarity index 100% rename from examples/02_blink/main/Kconfig.projbuild rename to examples/get-started/blink/main/Kconfig.projbuild diff --git a/examples/02_blink/main/blink.c b/examples/get-started/blink/main/blink.c similarity index 100% rename from examples/02_blink/main/blink.c rename to examples/get-started/blink/main/blink.c diff --git a/examples/05_ble_adv/main/component.mk b/examples/get-started/blink/main/component.mk similarity index 100% rename from examples/05_ble_adv/main/component.mk rename to examples/get-started/blink/main/component.mk diff --git a/examples/02_blink/sdkconfig.defaults b/examples/get-started/blink/sdkconfig.defaults similarity index 100% rename from examples/02_blink/sdkconfig.defaults rename to examples/get-started/blink/sdkconfig.defaults diff --git a/examples/01_hello_world/Makefile b/examples/get-started/hello_world/Makefile similarity index 100% rename from examples/01_hello_world/Makefile rename to examples/get-started/hello_world/Makefile diff --git a/examples/01_hello_world/README.md b/examples/get-started/hello_world/README.md similarity index 100% rename from examples/01_hello_world/README.md rename to examples/get-started/hello_world/README.md diff --git a/examples/01_hello_world/main/component.mk b/examples/get-started/hello_world/main/component.mk similarity index 100% rename from examples/01_hello_world/main/component.mk rename to examples/get-started/hello_world/main/component.mk diff --git a/examples/01_hello_world/main/hello_world_main.c b/examples/get-started/hello_world/main/hello_world_main.c similarity index 100% rename from examples/01_hello_world/main/hello_world_main.c rename to examples/get-started/hello_world/main/hello_world_main.c diff --git a/examples/peripherals/README.md b/examples/peripherals/README.md new file mode 100644 index 0000000000..fdb4444191 --- /dev/null +++ b/examples/peripherals/README.md @@ -0,0 +1,5 @@ +# Peripherals Examples + +This section provides examples how to configure and use ESP32’s internal peripherals like GPIO, UART, I2C, SPI, timers, counters, ADC / DAC, PWM, etc. + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/21_gpio/Makefile b/examples/peripherals/gpio/Makefile similarity index 100% rename from examples/21_gpio/Makefile rename to examples/peripherals/gpio/Makefile diff --git a/examples/21_gpio/README.md b/examples/peripherals/gpio/README.md similarity index 100% rename from examples/21_gpio/README.md rename to examples/peripherals/gpio/README.md diff --git a/examples/09_openssl_client/main/component.mk b/examples/peripherals/gpio/main/component.mk similarity index 100% rename from examples/09_openssl_client/main/component.mk rename to examples/peripherals/gpio/main/component.mk diff --git a/examples/21_gpio/main/gpio_test.c b/examples/peripherals/gpio/main/gpio_test.c similarity index 100% rename from examples/21_gpio/main/gpio_test.c rename to examples/peripherals/gpio/main/gpio_test.c diff --git a/examples/18_i2c/Makefile b/examples/peripherals/i2c/Makefile similarity index 100% rename from examples/18_i2c/Makefile rename to examples/peripherals/i2c/Makefile diff --git a/examples/18_i2c/README.md b/examples/peripherals/i2c/README.md similarity index 100% rename from examples/18_i2c/README.md rename to examples/peripherals/i2c/README.md diff --git a/examples/16_pcnt/main/component.mk b/examples/peripherals/i2c/main/component.mk similarity index 100% rename from examples/16_pcnt/main/component.mk rename to examples/peripherals/i2c/main/component.mk diff --git a/examples/18_i2c/main/i2c_test.c b/examples/peripherals/i2c/main/i2c_test.c similarity index 100% rename from examples/18_i2c/main/i2c_test.c rename to examples/peripherals/i2c/main/i2c_test.c diff --git a/examples/22_i2s/Makefile b/examples/peripherals/i2s/Makefile similarity index 100% rename from examples/22_i2s/Makefile rename to examples/peripherals/i2s/Makefile diff --git a/examples/22_i2s/main/app_main.c b/examples/peripherals/i2s/main/app_main.c similarity index 100% rename from examples/22_i2s/main/app_main.c rename to examples/peripherals/i2s/main/app_main.c diff --git a/examples/22_i2s/main/component.mk b/examples/peripherals/i2s/main/component.mk similarity index 100% rename from examples/22_i2s/main/component.mk rename to examples/peripherals/i2s/main/component.mk diff --git a/examples/29_ledc/Makefile b/examples/peripherals/ledc/Makefile similarity index 100% rename from examples/29_ledc/Makefile rename to examples/peripherals/ledc/Makefile diff --git a/examples/29_ledc/README.md b/examples/peripherals/ledc/README.md similarity index 100% rename from examples/29_ledc/README.md rename to examples/peripherals/ledc/README.md diff --git a/examples/18_i2c/main/component.mk b/examples/peripherals/ledc/main/component.mk similarity index 100% rename from examples/18_i2c/main/component.mk rename to examples/peripherals/ledc/main/component.mk diff --git a/examples/29_ledc/main/ledc_fade.c b/examples/peripherals/ledc/main/ledc_fade.c similarity index 100% rename from examples/29_ledc/main/ledc_fade.c rename to examples/peripherals/ledc/main/ledc_fade.c diff --git a/examples/16_pcnt/Makefile b/examples/peripherals/pcnt/Makefile similarity index 100% rename from examples/16_pcnt/Makefile rename to examples/peripherals/pcnt/Makefile diff --git a/examples/16_pcnt/README.md b/examples/peripherals/pcnt/README.md similarity index 100% rename from examples/16_pcnt/README.md rename to examples/peripherals/pcnt/README.md diff --git a/examples/20_uart/main/component.mk b/examples/peripherals/pcnt/main/component.mk similarity index 100% rename from examples/20_uart/main/component.mk rename to examples/peripherals/pcnt/main/component.mk diff --git a/examples/16_pcnt/main/pcnt_test.c b/examples/peripherals/pcnt/main/pcnt_test.c similarity index 100% rename from examples/16_pcnt/main/pcnt_test.c rename to examples/peripherals/pcnt/main/pcnt_test.c diff --git a/examples/11_rmt_nec_tx_rx/Makefile b/examples/peripherals/rmt_nec_tx_rx/Makefile similarity index 100% rename from examples/11_rmt_nec_tx_rx/Makefile rename to examples/peripherals/rmt_nec_tx_rx/Makefile diff --git a/examples/11_rmt_nec_tx_rx/README.md b/examples/peripherals/rmt_nec_tx_rx/README.md similarity index 100% rename from examples/11_rmt_nec_tx_rx/README.md rename to examples/peripherals/rmt_nec_tx_rx/README.md diff --git a/examples/11_rmt_nec_tx_rx/main/component.mk b/examples/peripherals/rmt_nec_tx_rx/main/component.mk similarity index 100% rename from examples/11_rmt_nec_tx_rx/main/component.mk rename to examples/peripherals/rmt_nec_tx_rx/main/component.mk diff --git a/examples/11_rmt_nec_tx_rx/main/infrared_nec.c b/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec.c similarity index 100% rename from examples/11_rmt_nec_tx_rx/main/infrared_nec.c rename to examples/peripherals/rmt_nec_tx_rx/main/infrared_nec.c diff --git a/examples/11_rmt_nec_tx_rx/main/infrared_nec_main.c b/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c similarity index 100% rename from examples/11_rmt_nec_tx_rx/main/infrared_nec_main.c rename to examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c diff --git a/examples/19_sigmadelta/Makefile b/examples/peripherals/sigmadelta/Makefile similarity index 100% rename from examples/19_sigmadelta/Makefile rename to examples/peripherals/sigmadelta/Makefile diff --git a/examples/19_sigmadelta/README.md b/examples/peripherals/sigmadelta/README.md similarity index 100% rename from examples/19_sigmadelta/README.md rename to examples/peripherals/sigmadelta/README.md diff --git a/examples/19_sigmadelta/main/component.mk b/examples/peripherals/sigmadelta/main/component.mk similarity index 100% rename from examples/19_sigmadelta/main/component.mk rename to examples/peripherals/sigmadelta/main/component.mk diff --git a/examples/19_sigmadelta/main/sigmadelta_test.c b/examples/peripherals/sigmadelta/main/sigmadelta_test.c similarity index 100% rename from examples/19_sigmadelta/main/sigmadelta_test.c rename to examples/peripherals/sigmadelta/main/sigmadelta_test.c diff --git a/examples/26_spi_master/Makefile b/examples/peripherals/spi_master/Makefile similarity index 100% rename from examples/26_spi_master/Makefile rename to examples/peripherals/spi_master/Makefile diff --git a/examples/26_spi_master/main/component.mk b/examples/peripherals/spi_master/main/component.mk similarity index 100% rename from examples/26_spi_master/main/component.mk rename to examples/peripherals/spi_master/main/component.mk diff --git a/examples/26_spi_master/main/spi_master.c b/examples/peripherals/spi_master/main/spi_master.c similarity index 100% rename from examples/26_spi_master/main/spi_master.c rename to examples/peripherals/spi_master/main/spi_master.c diff --git a/examples/13_timer_group/Makefile b/examples/peripherals/timer_group/Makefile similarity index 100% rename from examples/13_timer_group/Makefile rename to examples/peripherals/timer_group/Makefile diff --git a/examples/13_timer_group/README.md b/examples/peripherals/timer_group/README.md similarity index 100% rename from examples/13_timer_group/README.md rename to examples/peripherals/timer_group/README.md diff --git a/examples/07_nvs_rw_value/main/component.mk b/examples/peripherals/timer_group/main/component.mk similarity index 100% rename from examples/07_nvs_rw_value/main/component.mk rename to examples/peripherals/timer_group/main/component.mk diff --git a/examples/13_timer_group/main/timer_group.c b/examples/peripherals/timer_group/main/timer_group.c similarity index 100% rename from examples/13_timer_group/main/timer_group.c rename to examples/peripherals/timer_group/main/timer_group.c diff --git a/examples/20_uart/Makefile b/examples/peripherals/uart/Makefile similarity index 100% rename from examples/20_uart/Makefile rename to examples/peripherals/uart/Makefile diff --git a/examples/21_gpio/main/component.mk b/examples/peripherals/uart/main/component.mk similarity index 100% rename from examples/21_gpio/main/component.mk rename to examples/peripherals/uart/main/component.mk diff --git a/examples/20_uart/main/uart_test.c b/examples/peripherals/uart/main/uart_test.c similarity index 100% rename from examples/20_uart/main/uart_test.c rename to examples/peripherals/uart/main/uart_test.c diff --git a/examples/protocols/README.md b/examples/protocols/README.md new file mode 100644 index 0000000000..2c34c3da60 --- /dev/null +++ b/examples/protocols/README.md @@ -0,0 +1,5 @@ +# Protocols Examples + +Implementation of internet communication protocols and services. + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/23_coap_client/Makefile b/examples/protocols/coap_client/Makefile similarity index 100% rename from examples/23_coap_client/Makefile rename to examples/protocols/coap_client/Makefile diff --git a/examples/23_coap_client/main/Kconfig.projbuild b/examples/protocols/coap_client/main/Kconfig.projbuild similarity index 100% rename from examples/23_coap_client/main/Kconfig.projbuild rename to examples/protocols/coap_client/main/Kconfig.projbuild diff --git a/examples/23_coap_client/main/coap_client.c b/examples/protocols/coap_client/main/coap_client.c similarity index 100% rename from examples/23_coap_client/main/coap_client.c rename to examples/protocols/coap_client/main/coap_client.c diff --git a/examples/08_nvs_rw_blob/main/component.mk b/examples/protocols/coap_client/main/component.mk similarity index 100% rename from examples/08_nvs_rw_blob/main/component.mk rename to examples/protocols/coap_client/main/component.mk diff --git a/examples/24_coap_server/Makefile b/examples/protocols/coap_server/Makefile similarity index 100% rename from examples/24_coap_server/Makefile rename to examples/protocols/coap_server/Makefile diff --git a/examples/24_coap_server/main/Kconfig.projbuild b/examples/protocols/coap_server/main/Kconfig.projbuild similarity index 100% rename from examples/24_coap_server/main/Kconfig.projbuild rename to examples/protocols/coap_server/main/Kconfig.projbuild diff --git a/examples/24_coap_server/main/coap_server.c b/examples/protocols/coap_server/main/coap_server.c similarity index 100% rename from examples/24_coap_server/main/coap_server.c rename to examples/protocols/coap_server/main/coap_server.c diff --git a/examples/13_timer_group/main/component.mk b/examples/protocols/coap_server/main/component.mk similarity index 100% rename from examples/13_timer_group/main/component.mk rename to examples/protocols/coap_server/main/component.mk diff --git a/examples/03_http_request/Makefile b/examples/protocols/http_request/Makefile similarity index 100% rename from examples/03_http_request/Makefile rename to examples/protocols/http_request/Makefile diff --git a/examples/03_http_request/README.md b/examples/protocols/http_request/README.md similarity index 100% rename from examples/03_http_request/README.md rename to examples/protocols/http_request/README.md diff --git a/examples/03_http_request/main/Kconfig.projbuild b/examples/protocols/http_request/main/Kconfig.projbuild similarity index 100% rename from examples/03_http_request/main/Kconfig.projbuild rename to examples/protocols/http_request/main/Kconfig.projbuild diff --git a/examples/06_sntp/main/component.mk b/examples/protocols/http_request/main/component.mk similarity index 100% rename from examples/06_sntp/main/component.mk rename to examples/protocols/http_request/main/component.mk diff --git a/examples/03_http_request/main/http_request_main.c b/examples/protocols/http_request/main/http_request_main.c similarity index 100% rename from examples/03_http_request/main/http_request_main.c rename to examples/protocols/http_request/main/http_request_main.c diff --git a/examples/04_https_request/Makefile b/examples/protocols/https_request/Makefile similarity index 100% rename from examples/04_https_request/Makefile rename to examples/protocols/https_request/Makefile diff --git a/examples/04_https_request/README.md b/examples/protocols/https_request/README.md similarity index 100% rename from examples/04_https_request/README.md rename to examples/protocols/https_request/README.md diff --git a/examples/04_https_request/main/Kconfig.projbuild b/examples/protocols/https_request/main/Kconfig.projbuild similarity index 100% rename from examples/04_https_request/main/Kconfig.projbuild rename to examples/protocols/https_request/main/Kconfig.projbuild diff --git a/examples/04_https_request/main/component.mk b/examples/protocols/https_request/main/component.mk similarity index 100% rename from examples/04_https_request/main/component.mk rename to examples/protocols/https_request/main/component.mk diff --git a/examples/04_https_request/main/https_request_main.c b/examples/protocols/https_request/main/https_request_main.c similarity index 100% rename from examples/04_https_request/main/https_request_main.c rename to examples/protocols/https_request/main/https_request_main.c diff --git a/examples/04_https_request/main/server_root_cert.pem b/examples/protocols/https_request/main/server_root_cert.pem similarity index 100% rename from examples/04_https_request/main/server_root_cert.pem rename to examples/protocols/https_request/main/server_root_cert.pem diff --git a/examples/30_mdns_example/Makefile b/examples/protocols/mdns/Makefile similarity index 100% rename from examples/30_mdns_example/Makefile rename to examples/protocols/mdns/Makefile diff --git a/examples/30_mdns_example/README.md b/examples/protocols/mdns/README.md similarity index 90% rename from examples/30_mdns_example/README.md rename to examples/protocols/mdns/README.md index 1c298604b8..76dbdc17b7 100644 --- a/examples/30_mdns_example/README.md +++ b/examples/protocols/mdns/README.md @@ -1,4 +1,4 @@ -# 30_mdns example +# mDNS example Shows how to use mDNS to advertise lookup services and hosts diff --git a/examples/30_mdns_example/main/Kconfig.projbuild b/examples/protocols/mdns/main/Kconfig.projbuild similarity index 100% rename from examples/30_mdns_example/main/Kconfig.projbuild rename to examples/protocols/mdns/main/Kconfig.projbuild diff --git a/examples/17_ethernet/main/component.mk b/examples/protocols/mdns/main/component.mk similarity index 100% rename from examples/17_ethernet/main/component.mk rename to examples/protocols/mdns/main/component.mk diff --git a/examples/30_mdns_example/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c similarity index 100% rename from examples/30_mdns_example/main/mdns_example_main.c rename to examples/protocols/mdns/main/mdns_example_main.c diff --git a/examples/09_openssl_client/Makefile b/examples/protocols/openssl_client/Makefile similarity index 100% rename from examples/09_openssl_client/Makefile rename to examples/protocols/openssl_client/Makefile diff --git a/examples/09_openssl_client/README.md b/examples/protocols/openssl_client/README.md similarity index 100% rename from examples/09_openssl_client/README.md rename to examples/protocols/openssl_client/README.md diff --git a/examples/09_openssl_client/main/Kconfig.projbuild b/examples/protocols/openssl_client/main/Kconfig.projbuild similarity index 100% rename from examples/09_openssl_client/main/Kconfig.projbuild rename to examples/protocols/openssl_client/main/Kconfig.projbuild diff --git a/examples/29_ledc/main/component.mk b/examples/protocols/openssl_client/main/component.mk similarity index 100% rename from examples/29_ledc/main/component.mk rename to examples/protocols/openssl_client/main/component.mk diff --git a/examples/09_openssl_client/main/openssl_client.c b/examples/protocols/openssl_client/main/openssl_client.c similarity index 100% rename from examples/09_openssl_client/main/openssl_client.c rename to examples/protocols/openssl_client/main/openssl_client.c diff --git a/examples/09_openssl_client/main/openssl_client.h b/examples/protocols/openssl_client/main/openssl_client.h similarity index 100% rename from examples/09_openssl_client/main/openssl_client.h rename to examples/protocols/openssl_client/main/openssl_client.h diff --git a/examples/10_openssl_server/Makefile b/examples/protocols/openssl_server/Makefile similarity index 100% rename from examples/10_openssl_server/Makefile rename to examples/protocols/openssl_server/Makefile diff --git a/examples/10_openssl_server/README.md b/examples/protocols/openssl_server/README.md similarity index 100% rename from examples/10_openssl_server/README.md rename to examples/protocols/openssl_server/README.md diff --git a/examples/10_openssl_server/main/Kconfig.projbuild b/examples/protocols/openssl_server/main/Kconfig.projbuild similarity index 100% rename from examples/10_openssl_server/main/Kconfig.projbuild rename to examples/protocols/openssl_server/main/Kconfig.projbuild diff --git a/examples/10_openssl_server/main/cacert.pem b/examples/protocols/openssl_server/main/cacert.pem similarity index 100% rename from examples/10_openssl_server/main/cacert.pem rename to examples/protocols/openssl_server/main/cacert.pem diff --git a/examples/10_openssl_server/main/component.mk b/examples/protocols/openssl_server/main/component.mk similarity index 100% rename from examples/10_openssl_server/main/component.mk rename to examples/protocols/openssl_server/main/component.mk diff --git a/examples/10_openssl_server/main/openssl_server.c b/examples/protocols/openssl_server/main/openssl_server.c similarity index 96% rename from examples/10_openssl_server/main/openssl_server.c rename to examples/protocols/openssl_server/main/openssl_server.c index 1eea2110ce..c74bb0e41f 100755 --- a/examples/10_openssl_server/main/openssl_server.c +++ b/examples/protocols/openssl_server/main/openssl_server.c @@ -37,7 +37,7 @@ const static char *TAG = "Openssl_demo"; #define OPENSSL_DEMO_SERVER_ACK "HTTP/1.1 200 OK\r\n" \ "Content-Type: text/html\r\n" \ - "Content-Length: 98\r\n" \ + "Content-Length: 98\r\n\r\n" \ "\r\n" \ "\r\n" \ "OpenSSL demo\r\n" \ @@ -71,6 +71,10 @@ static void openssl_demo_thread(void *p) const unsigned int prvtkey_pem_bytes = prvtkey_pem_end - prvtkey_pem_start; ESP_LOGI(TAG, "SSL server context create ......"); + /* For security reasons, it is best if you can use + TLSv1_2_server_method() here instead of TLS_server_method(). + However some old browsers may not support TLS v1.2. + */ ctx = SSL_CTX_new(TLS_server_method()); if (!ctx) { ESP_LOGI(TAG, "failed"); diff --git a/examples/10_openssl_server/main/openssl_server.h b/examples/protocols/openssl_server/main/openssl_server.h similarity index 100% rename from examples/10_openssl_server/main/openssl_server.h rename to examples/protocols/openssl_server/main/openssl_server.h diff --git a/examples/10_openssl_server/main/prvtkey.pem b/examples/protocols/openssl_server/main/prvtkey.pem similarity index 100% rename from examples/10_openssl_server/main/prvtkey.pem rename to examples/protocols/openssl_server/main/prvtkey.pem diff --git a/examples/06_sntp/Makefile b/examples/protocols/sntp/Makefile similarity index 100% rename from examples/06_sntp/Makefile rename to examples/protocols/sntp/Makefile diff --git a/examples/06_sntp/README.md b/examples/protocols/sntp/README.md similarity index 100% rename from examples/06_sntp/README.md rename to examples/protocols/sntp/README.md diff --git a/examples/06_sntp/main/Kconfig.projbuild b/examples/protocols/sntp/main/Kconfig.projbuild similarity index 100% rename from examples/06_sntp/main/Kconfig.projbuild rename to examples/protocols/sntp/main/Kconfig.projbuild diff --git a/examples/25_ota/main/component.mk b/examples/protocols/sntp/main/component.mk similarity index 100% rename from examples/25_ota/main/component.mk rename to examples/protocols/sntp/main/component.mk diff --git a/examples/06_sntp/main/sntp_main.c b/examples/protocols/sntp/main/sntp_main.c similarity index 99% rename from examples/06_sntp/main/sntp_main.c rename to examples/protocols/sntp/main/sntp_main.c index f128323dcb..438505d7b6 100644 --- a/examples/06_sntp/main/sntp_main.c +++ b/examples/protocols/sntp/main/sntp_main.c @@ -110,6 +110,8 @@ static void obtain_time(void) time(&now); localtime_r(&now, &timeinfo); } + + ESP_ERROR_CHECK( esp_wifi_stop() ); } static void initialize_sntp(void) diff --git a/examples/storage/README.md b/examples/storage/README.md new file mode 100644 index 0000000000..36b1f64b27 --- /dev/null +++ b/examples/storage/README.md @@ -0,0 +1,5 @@ +# Storage Examples + +Storage and management of user and system data in module’s flash and on external memory / devices. + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/08_nvs_rw_blob/Makefile b/examples/storage/nvs_rw_blob/Makefile similarity index 100% rename from examples/08_nvs_rw_blob/Makefile rename to examples/storage/nvs_rw_blob/Makefile diff --git a/examples/08_nvs_rw_blob/README.md b/examples/storage/nvs_rw_blob/README.md similarity index 85% rename from examples/08_nvs_rw_blob/README.md rename to examples/storage/nvs_rw_blob/README.md index 81a0e36c71..94b8549b36 100644 --- a/examples/08_nvs_rw_blob/README.md +++ b/examples/storage/nvs_rw_blob/README.md @@ -7,7 +7,7 @@ Demonstrates how to read and write a single integer value and a blob (binary lar Example also shows how to implement diagnostics if read / write operation was successful. -If not done already, consider checking simpler example *07_nvs_rw_value*, that has been used as a starting point for preparing this one. +If not done already, consider checking simpler example *storage/nvs_rw_value*, that has been used as a starting point for preparing this one. Detailed functional description of NVS and API is provided in [documentation](http://esp-idf.readthedocs.io/en/latest/api/nvs_flash.html). diff --git a/examples/23_coap_client/main/component.mk b/examples/storage/nvs_rw_blob/main/component.mk similarity index 100% rename from examples/23_coap_client/main/component.mk rename to examples/storage/nvs_rw_blob/main/component.mk diff --git a/examples/08_nvs_rw_blob/main/nvs_rw_blob.c b/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c similarity index 100% rename from examples/08_nvs_rw_blob/main/nvs_rw_blob.c rename to examples/storage/nvs_rw_blob/main/nvs_rw_blob.c index 0d4b7db4ee..c0a865eb6a 100644 --- a/examples/08_nvs_rw_blob/main/nvs_rw_blob.c +++ b/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c @@ -87,10 +87,10 @@ esp_err_t save_run_time(void) required_size += sizeof(uint32_t); run_time[required_size / sizeof(uint32_t) - 1] = xTaskGetTickCount() * portTICK_PERIOD_MS; err = nvs_set_blob(my_handle, "run_time", run_time, required_size); - if (err != ESP_OK) return err; - free(run_time); + if (err != ESP_OK) return err; + // Commit err = nvs_commit(my_handle); if (err != ESP_OK) return err; diff --git a/examples/07_nvs_rw_value/Makefile b/examples/storage/nvs_rw_value/Makefile similarity index 100% rename from examples/07_nvs_rw_value/Makefile rename to examples/storage/nvs_rw_value/Makefile diff --git a/examples/07_nvs_rw_value/README.md b/examples/storage/nvs_rw_value/README.md similarity index 86% rename from examples/07_nvs_rw_value/README.md rename to examples/storage/nvs_rw_value/README.md index 09cd364e8d..797e8d422a 100644 --- a/examples/07_nvs_rw_value/README.md +++ b/examples/storage/nvs_rw_value/README.md @@ -6,7 +6,7 @@ The value holds the number of ESP32 module restarts. Since it is written to NVS, Example also shows how to check if read / write operation was successful, or certain value is not initialized in NVS. Diagnostic is provided in plain text to help track program flow and capture any issues on the way. -Check another example *08_nvs_rw_blob*, that shows how to read and write variable length binary data (blob). +Check another example *storage/nvs_rw_blob*, that shows how to read and write variable length binary data (blob). Detailed functional description of NVS and API is provided in [documentation](http://esp-idf.readthedocs.io/en/latest/api/nvs_flash.html). diff --git a/examples/24_coap_server/main/component.mk b/examples/storage/nvs_rw_value/main/component.mk similarity index 100% rename from examples/24_coap_server/main/component.mk rename to examples/storage/nvs_rw_value/main/component.mk diff --git a/examples/07_nvs_rw_value/main/nvs_rw_value.c b/examples/storage/nvs_rw_value/main/nvs_rw_value.c similarity index 100% rename from examples/07_nvs_rw_value/main/nvs_rw_value.c rename to examples/storage/nvs_rw_value/main/nvs_rw_value.c diff --git a/examples/27_sd_card/Makefile b/examples/storage/sd_card/Makefile similarity index 100% rename from examples/27_sd_card/Makefile rename to examples/storage/sd_card/Makefile diff --git a/examples/27_sd_card/README.md b/examples/storage/sd_card/README.md similarity index 98% rename from examples/27_sd_card/README.md rename to examples/storage/sd_card/README.md index bfc6a39fe9..b125716eae 100644 --- a/examples/27_sd_card/README.md +++ b/examples/storage/sd_card/README.md @@ -32,7 +32,8 @@ N/C | WP | This example doesn't utilize card detect (CD) and write protect (WP) signals from SD card slot. ### Note about GPIO2 -GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART download mode. One way to do this is to connect GPIO0 and GPIO2 using a jumper, and then the auto-reset circuit on most development boards will pull GPIO2 low along with GPIO2, when entering download mode. + +GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART download mode. One way to do this is to connect GPIO0 and GPIO2 using a jumper, and then the auto-reset circuit on most development boards will pull GPIO2 low along with GPIO0, when entering download mode. ### Note about GPIO12 diff --git a/examples/27_sd_card/main/component.mk b/examples/storage/sd_card/main/component.mk similarity index 100% rename from examples/27_sd_card/main/component.mk rename to examples/storage/sd_card/main/component.mk diff --git a/examples/27_sd_card/main/sd_card.c b/examples/storage/sd_card/main/sd_card.c similarity index 100% rename from examples/27_sd_card/main/sd_card.c rename to examples/storage/sd_card/main/sd_card.c diff --git a/examples/system/README.md b/examples/system/README.md new file mode 100644 index 0000000000..3fb812f307 --- /dev/null +++ b/examples/system/README.md @@ -0,0 +1,5 @@ +# System Examples + +Configuration and management of memory, interrupts, WDT (watchdog timer), OTA (over the air updates), deep sleep and logging. + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/25_ota/Makefile b/examples/system/ota/Makefile similarity index 100% rename from examples/25_ota/Makefile rename to examples/system/ota/Makefile diff --git a/examples/25_ota/OTA_workflow.png b/examples/system/ota/OTA_workflow.png similarity index 100% rename from examples/25_ota/OTA_workflow.png rename to examples/system/ota/OTA_workflow.png diff --git a/examples/25_ota/README.md b/examples/system/ota/README.md similarity index 97% rename from examples/25_ota/README.md rename to examples/system/ota/README.md index 49a47d3799..886dbf5fbb 100644 --- a/examples/25_ota/README.md +++ b/examples/system/ota/README.md @@ -30,12 +30,12 @@ Connect your host PC to the same AP that you will use for the ESP32. Python has a built-in HTTP server that can be used for example purposes. -For our upgrade example OTA file, we're going to use the `01_hello_world` example. +For our upgrade example OTA file, we're going to use the `get-started/hello_world` example. Open a new terminal to run the HTTP server, then run these commands to build the example and start the server: ``` -cd $IDF_PATH/examples/01_hello_world +cd $IDF_PATH/examples/get-started/hello_world make cd build python -m SimpleHTTPServer 8070 diff --git a/examples/25_ota/main/Kconfig.projbuild b/examples/system/ota/main/Kconfig.projbuild similarity index 100% rename from examples/25_ota/main/Kconfig.projbuild rename to examples/system/ota/main/Kconfig.projbuild diff --git a/examples/30_mdns_example/main/component.mk b/examples/system/ota/main/component.mk similarity index 100% rename from examples/30_mdns_example/main/component.mk rename to examples/system/ota/main/component.mk diff --git a/examples/25_ota/main/ota.c b/examples/system/ota/main/ota.c similarity index 91% rename from examples/25_ota/main/ota.c rename to examples/system/ota/main/ota.c index 4956129e5d..2dfda1c828 100644 --- a/examples/25_ota/main/ota.c +++ b/examples/system/ota/main/ota.c @@ -95,7 +95,7 @@ static void initialise_wifi(void) } /*read buffer by byte still delim ,return read bytes counts*/ -int read_until(char *buffer, char delim, int len) +static int read_until(char *buffer, char delim, int len) { // /*TODO: delim check,buffer check,further: do an buffer length limited*/ int i = 0; @@ -109,7 +109,7 @@ int read_until(char *buffer, char delim, int len) * return true if packet including \r\n\r\n that means http packet header finished,start to receive packet body * otherwise return false * */ -bool resolve_pkg(char text[], int total_len, esp_ota_handle_t out_handle) +static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t out_handle) { /* i means current position */ int i = 0, i_read_len = 0; @@ -121,17 +121,10 @@ bool resolve_pkg(char text[], int total_len, esp_ota_handle_t out_handle) memset(ota_write_data, 0, BUFFSIZE); /*copy first http packet body to write buffer*/ memcpy(ota_write_data, &(text[i + 2]), i_write_len); - /*check write packet header first byte:0xE9 second byte:0x09 */ - if (ota_write_data[0] == 0xE9 && i_write_len >= 2 && ota_write_data[1] == 0x09) { - ESP_LOGI(TAG, "OTA Write Header format Check OK. first byte is %02x ,second byte is %02x", ota_write_data[0], ota_write_data[1]); - } else { - ESP_LOGE(TAG, "OTA Write Header format Check Failed! first byte is %02x ,second byte is %02x", ota_write_data[0], ota_write_data[1]); - return false; - } esp_err_t err = esp_ota_write( out_handle, (const void *)ota_write_data, i_write_len); if (err != ESP_OK) { - ESP_LOGE(TAG, "Error: esp_ota_write failed! err=%x", err); + ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err); return false; } else { ESP_LOGI(TAG, "esp_ota_write header OK"); @@ -266,7 +259,7 @@ void main_task(void *pvParameter) task_fatal_error(); } - bool pkg_body_start = false, flag = true; + bool resp_body_start = false, flag = true; /*deal with all receive packet*/ while (flag) { memset(text, 0, TEXT_BUFFSIZE); @@ -275,14 +268,14 @@ void main_task(void *pvParameter) if (buff_len < 0) { /*receive error*/ ESP_LOGE(TAG, "Error: receive data error! errno=%d", errno); task_fatal_error(); - } else if (buff_len > 0 && !pkg_body_start) { /*deal with packet header*/ + } else if (buff_len > 0 && !resp_body_start) { /*deal with response header*/ memcpy(ota_write_data, text, buff_len); - pkg_body_start = resolve_pkg(text, buff_len, out_handle); - } else if (buff_len > 0 && pkg_body_start) { /*deal with packet body*/ + resp_body_start = read_past_http_header(text, buff_len, out_handle); + } else if (buff_len > 0 && resp_body_start) { /*deal with response body*/ memcpy(ota_write_data, text, buff_len); err = esp_ota_write( out_handle, (const void *)ota_write_data, buff_len); if (err != ESP_OK) { - ESP_LOGE(TAG, "Error: esp_ota_write failed! err=%x", err); + ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err); task_fatal_error(); } binary_file_length += buff_len; diff --git a/examples/25_ota/sdkconfig.defaults b/examples/system/ota/sdkconfig.defaults similarity index 100% rename from examples/25_ota/sdkconfig.defaults rename to examples/system/ota/sdkconfig.defaults diff --git a/examples/wifi/README.md b/examples/wifi/README.md new file mode 100644 index 0000000000..b0dc683508 --- /dev/null +++ b/examples/wifi/README.md @@ -0,0 +1,3 @@ +# Wi-Fi Examples + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/31_wpa2_enterprise/Makefile b/examples/wifi/wpa2_enterprise/Makefile similarity index 100% rename from examples/31_wpa2_enterprise/Makefile rename to examples/wifi/wpa2_enterprise/Makefile diff --git a/examples/31_wpa2_enterprise/README.md b/examples/wifi/wpa2_enterprise/README.md similarity index 100% rename from examples/31_wpa2_enterprise/README.md rename to examples/wifi/wpa2_enterprise/README.md diff --git a/examples/31_wpa2_enterprise/main/Kconfig.projbuild b/examples/wifi/wpa2_enterprise/main/Kconfig.projbuild similarity index 100% rename from examples/31_wpa2_enterprise/main/Kconfig.projbuild rename to examples/wifi/wpa2_enterprise/main/Kconfig.projbuild diff --git a/examples/31_wpa2_enterprise/main/component.mk b/examples/wifi/wpa2_enterprise/main/component.mk similarity index 100% rename from examples/31_wpa2_enterprise/main/component.mk rename to examples/wifi/wpa2_enterprise/main/component.mk diff --git a/examples/31_wpa2_enterprise/main/wpa2_ca.pem b/examples/wifi/wpa2_enterprise/main/wpa2_ca.pem similarity index 100% rename from examples/31_wpa2_enterprise/main/wpa2_ca.pem rename to examples/wifi/wpa2_enterprise/main/wpa2_ca.pem diff --git a/examples/31_wpa2_enterprise/main/wpa2_client.crt b/examples/wifi/wpa2_enterprise/main/wpa2_client.crt similarity index 100% rename from examples/31_wpa2_enterprise/main/wpa2_client.crt rename to examples/wifi/wpa2_enterprise/main/wpa2_client.crt diff --git a/examples/31_wpa2_enterprise/main/wpa2_client.key b/examples/wifi/wpa2_enterprise/main/wpa2_client.key similarity index 100% rename from examples/31_wpa2_enterprise/main/wpa2_client.key rename to examples/wifi/wpa2_enterprise/main/wpa2_client.key diff --git a/examples/31_wpa2_enterprise/main/wpa2_client.pem b/examples/wifi/wpa2_enterprise/main/wpa2_client.pem similarity index 100% rename from examples/31_wpa2_enterprise/main/wpa2_client.pem rename to examples/wifi/wpa2_enterprise/main/wpa2_client.pem diff --git a/examples/31_wpa2_enterprise/main/wpa2_enterprise_main.c b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c similarity index 100% rename from examples/31_wpa2_enterprise/main/wpa2_enterprise_main.c rename to examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c diff --git a/examples/31_wpa2_enterprise/main/wpa2_server.crt b/examples/wifi/wpa2_enterprise/main/wpa2_server.crt similarity index 100% rename from examples/31_wpa2_enterprise/main/wpa2_server.crt rename to examples/wifi/wpa2_enterprise/main/wpa2_server.crt diff --git a/examples/31_wpa2_enterprise/main/wpa2_server.key b/examples/wifi/wpa2_enterprise/main/wpa2_server.key similarity index 100% rename from examples/31_wpa2_enterprise/main/wpa2_server.key rename to examples/wifi/wpa2_enterprise/main/wpa2_server.key diff --git a/examples/31_wpa2_enterprise/main/wpa2_server.pem b/examples/wifi/wpa2_enterprise/main/wpa2_server.pem similarity index 100% rename from examples/31_wpa2_enterprise/main/wpa2_server.pem rename to examples/wifi/wpa2_enterprise/main/wpa2_server.pem diff --git a/make/build_examples.sh b/make/build_examples.sh index ab59208795..ee429309e1 100755 --- a/make/build_examples.sh +++ b/make/build_examples.sh @@ -9,40 +9,47 @@ # [ -z ${IDF_PATH} ] && echo "IDF_PATH is not set" && exit 1 +export BATCH_BUILD=1 +export V=0 # only build verbose if there's an error + EXAMPLE_NUM=1 RESULT=0 FAILED_EXAMPLES="" RESULT_WARNINGS=22 # magic number result code for "warnings found" -for example in ${IDF_PATH}/examples/*; do - [ -f ${example}/Makefile ] || continue - echo "Building ${example} as ${EXAMPLE_NUM}..." - mkdir -p example_builds/${EXAMPLE_NUM} - cp -r ${example} example_builds/${EXAMPLE_NUM} - pushd example_builds/${EXAMPLE_NUM}/`basename ${example}` +# traverse categories +for category in ${IDF_PATH}/examples/*; do + # traverse examples within each category + for example in ${category}/*; do + [ -f ${example}/Makefile ] || continue + echo "Building ${example} as ${EXAMPLE_NUM}..." + mkdir -p example_builds/${EXAMPLE_NUM} + cp -r ${example} example_builds/${EXAMPLE_NUM} + pushd example_builds/${EXAMPLE_NUM}/`basename ${example}` - # be stricter in the CI build than the default IDF settings - export EXTRA_CFLAGS="-Werror -Werror=deprecated-declarations" - export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + # be stricter in the CI build than the default IDF settings + export EXTRA_CFLAGS="-Werror -Werror=deprecated-declarations" + export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} - # build non-verbose first - BUILDLOG=$(mktemp -t examplebuild.XXXX.log) - ( - set -o pipefail # so result of make all isn't lost when piping to tee - set -e - make clean defconfig - make $* all 2>&1 | tee $BUILDLOG - ) || { RESULT=$?; FAILED_EXAMPLES+=" ${example}"; make V=1; } # only build verbose if there's an error - popd - EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 )) + # build non-verbose first + BUILDLOG=$(mktemp -t examplebuild.XXXX.log) + ( + set -o pipefail # so result of make all isn't lost when piping to tee + set -e + make clean defconfig + make $* all 2>&1 | tee $BUILDLOG + ) || { RESULT=$?; FAILED_EXAMPLES+=" ${example}"; make V=1; } # verbose output for errors + popd + EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 )) - if grep -q ": warning:" $BUILDLOG; then - [ $RESULT -eq 0 ] && RESULT=$RESULT_WARNINGS - FAILED_EXAMPLES+=" ${example} (warnings)" - fi + if grep -q ": warning:" $BUILDLOG; then + [ $RESULT -eq 0 ] && RESULT=$RESULT_WARNINGS + FAILED_EXAMPLES+=" ${example} (warnings)" + fi - rm -f $BUILDLOG + rm -f $BUILDLOG + done done if [ $RESULT -eq $RESULT_WARNINGS ]; then diff --git a/make/common.mk b/make/common.mk index 605b8ab862..41a87b3a64 100644 --- a/make/common.mk +++ b/make/common.mk @@ -7,9 +7,14 @@ # (Note that we only rebuild this makefile automatically for some # targets, see project_config.mk for details.) SDKCONFIG_MAKEFILE ?= $(abspath $(BUILD_DIR_BASE)/include/config/auto.conf) --include $(SDKCONFIG_MAKEFILE) +include $(SDKCONFIG_MAKEFILE) export SDKCONFIG_MAKEFILE # sub-makes (like bootloader) will reuse this path +# BATCH_BUILD flag disables interactive terminal features, defaults to verbose build +ifdef BATCH_BUILD +V ?= 1 +endif + #Handling of V=1/VERBOSE=1 flag # # if V=1, $(summary) does nothing and $(details) will echo extra details diff --git a/make/project.mk b/make/project.mk index c4c3022a6b..04015a8a8c 100644 --- a/make/project.mk +++ b/make/project.mk @@ -49,14 +49,23 @@ endif # make IDF_PATH a "real" absolute path # * works around the case where a shell character is embedded in the environment variable value. # * changes Windows-style C:/blah/ paths to MSYS/Cygwin style /c/blah -export IDF_PATH:=$(realpath $(wildcard $(IDF_PATH))) +ifeq ("$(OS)","Windows_NT") +# On Windows MSYS2, make wildcard function returns empty string for paths of form /xyz +# where /xyz is a directory inside the MSYS root - so we don't use it. +SANITISED_IDF_PATH:=$(realpath $(IDF_PATH)) +else +SANITISED_IDF_PATH:=$(realpath $(wildcard $(IDF_PATH))) +endif + +export IDF_PATH := $(SANITISED_IDF_PATH) ifndef IDF_PATH $(error IDF_PATH variable is not set to a valid directory.) endif -ifneq ("$(IDF_PATH)","$(realpath $(wildcard $(IDF_PATH)))") -# due to the way make manages variables, this is hard to account for +ifneq ("$(IDF_PATH)","$(SANITISED_IDF_PATH)") +# implies IDF_PATH was overriden on make command line. +# Due to the way make manages variables, this is hard to account for # # if you see this error, do the shell expansion in the shell ie # make IDF_PATH=~/blah not make IDF_PATH="~/blah" @@ -370,12 +379,7 @@ $(BUILD_DIR_BASE)/$(2)/lib$(2).a: $(2)-build # If any component_project_vars.mk file is out of date, the make # process will call this target to rebuild it and then restart. # -# Note: $(SDKCONFIG) is a normal prereq as we need to rebuild these -# files whenever the config changes. $(SDKCONFIG_MAKEFILE) is an -# order-only prereq because if it hasn't been rebuilt, we need to -# build it first - but including it as a normal prereq can lead to -# infinite restarts as the conf process will keep updating it. -$(BUILD_DIR_BASE)/$(2)/component_project_vars.mk: $(1)/component.mk $(COMMON_MAKEFILES) $(SDKCONFIG) | $(BUILD_DIR_BASE)/$(2) $(SDKCONFIG_MAKEFILE) +$(BUILD_DIR_BASE)/$(2)/component_project_vars.mk: $(1)/component.mk $(COMMON_MAKEFILES) $(SDKCONFIG_MAKEFILE) | $(BUILD_DIR_BASE)/$(2) $(call ComponentMake,$(1),$(2)) component_project_vars.mk endef @@ -430,8 +434,8 @@ $(foreach submodule,$(subst $(IDF_PATH)/,,$(filter $(IDF_PATH)/%,$(COMPONENT_SUB # the part after the brackets is extracted into TOOLCHAIN_GCC_VER. ifdef CONFIG_TOOLPREFIX ifndef MAKE_RESTARTS -TOOLCHAIN_COMMIT_DESC := $(shell $(CC) --version | sed -E -n 's|xtensa-esp32-elf-gcc.*?\ \(([^)]*).*|\1|gp') -TOOLCHAIN_GCC_VER := $(shell $(CC) --version | sed -E -n 's|xtensa-esp32-elf-gcc.*?\ \(.*\)\ (.*)|\1|gp') +TOOLCHAIN_COMMIT_DESC := $(shell $(CC) --version | sed -E -n 's|xtensa-esp32-elf-gcc.*\ \(([^)]*).*|\1|gp') +TOOLCHAIN_GCC_VER := $(shell $(CC) --version | sed -E -n 's|xtensa-esp32-elf-gcc.*\ \(.*\)\ (.*)|\1|gp') # Officially supported version(s) SUPPORTED_TOOLCHAIN_COMMIT_DESC := crosstool-NG crosstool-ng-1.22.0-61-gab8375a diff --git a/make/project_config.mk b/make/project_config.mk index 011aa1ff0e..c0369f95f8 100644 --- a/make/project_config.mk +++ b/make/project_config.mk @@ -20,59 +20,77 @@ $(KCONFIG_TOOL_DIR)/mconf $(KCONFIG_TOOL_DIR)/conf: MAKEFLAGS=$(ORIGINAL_MAKEFLAGS) CC=$(HOSTCC) LD=$(HOSTLD) \ $(MAKE) -C $(KCONFIG_TOOL_DIR) -# use a wrapper environment for where we run Kconfig tools -KCONFIG_TOOL_ENV=KCONFIG_AUTOHEADER=$(abspath $(BUILD_DIR_BASE)/include/sdkconfig.h) \ - COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" KCONFIG_CONFIG=$(SDKCONFIG) \ - COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)" - -menuconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig $(call prereq_if_explicit,defconfig) - $(summary) MENUCONFIG - $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig - ifeq ("$(wildcard $(SDKCONFIG))","") -ifeq ("$(call prereq_if_explicit,defconfig)","") -# if not configuration is present and defconfig is not a target, run defconfig then menuconfig -$(SDKCONFIG): defconfig menuconfig +ifeq ("$(filter defconfig, $(MAKECMDGOALS))","") +# if no configuration file is present and defconfig is not a named +# target, run defconfig then menuconfig to get the initial config +$(SDKCONFIG): menuconfig +menuconfig: defconfig else -# otherwise, just defconfig +# otherwise, just run defconfig $(SDKCONFIG): defconfig endif endif +# macro for the commands to run kconfig tools conf or mconf. +# $1 is the name (& args) of the conf tool to run +define RunConf + mkdir -p $(BUILD_DIR_BASE)/include/config + cd $(BUILD_DIR_BASE); KCONFIG_AUTOHEADER=$(abspath $(BUILD_DIR_BASE)/include/sdkconfig.h) \ + COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" KCONFIG_CONFIG=$(SDKCONFIG) \ + COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)" \ + $(KCONFIG_TOOL_DIR)/$1 $(IDF_PATH)/Kconfig +endef + +ifeq ("$(MAKE_RESTARTS)","") +# menuconfig, defconfig and "GENCONFIG" configuration generation only +# ever run on the first make pass, subsequent passes don't run these +# (make often wants to re-run them as the conf tool can regenerate the +# sdkconfig input file as an output file, but this is not what the +# user wants - a single config pass is enough to produce all output +# files.) +# +# To prevent problems missing genconfig, ensure none of these targets +# depend on any prerequisite that may cause a make restart as part of +# the prerequisite's own recipe. + +menuconfig: $(KCONFIG_TOOL_DIR)/mconf + $(summary) MENUCONFIG +ifdef BATCH_BUILD + @echo "Can't run interactive configuration inside non-interactive build process." + @echo "" + @echo "Open a command line terminal and run 'make menuconfig' from there." + @echo "See esp-idf documentation for more details." + @exit 1 +else + $(call RunConf,mconf) +endif + # defconfig creates a default config, based on SDKCONFIG_DEFAULTS if present -defconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig $(BUILD_DIR_BASE) +defconfig: $(KCONFIG_TOOL_DIR)/conf $(summary) DEFCONFIG ifneq ("$(wildcard $(SDKCONFIG_DEFAULTS))","") cat $(SDKCONFIG_DEFAULTS) >> $(SDKCONFIG) # append defaults to sdkconfig, will override existing values endif - mkdir -p $(BUILD_DIR_BASE)/include/config - $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/conf --olddefconfig $(IDF_PATH)/Kconfig + $(call RunConf,conf --olddefconfig) -# Work out of whether we have to build the Kconfig makefile -# (auto.conf), or if we're in a situation where we don't need it -NON_CONFIG_TARGETS := clean %-clean help menuconfig defconfig -AUTO_CONF_REGEN_TARGET := $(SDKCONFIG_MAKEFILE) - -# disable AUTO_CONF_REGEN_TARGET if all targets are non-config targets -# (and not building default target) -ifneq ("$(MAKECMDGOALS)","") -ifeq ($(filter $(NON_CONFIG_TARGETS), $(MAKECMDGOALS)),$(MAKECMDGOALS)) -AUTO_CONF_REGEN_TARGET := -# dummy target -$(SDKCONFIG_MAKEFILE): -endif -endif - -$(AUTO_CONF_REGEN_TARGET) $(BUILD_DIR_BASE)/include/sdkconfig.h: $(SDKCONFIG) $(KCONFIG_TOOL_DIR)/conf $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD) +# if neither defconfig or menuconfig are requested, use the GENCONFIG rule to +# ensure generated config files are up to date +$(SDKCONFIG_MAKEFILE) $(BUILD_DIR_BASE)/include/sdkconfig.h: $(KCONFIG_TOOL_DIR)/conf $(SDKCONFIG) $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD) | $(call prereq_if_explicit,defconfig) $(call prereq_if_explicit,menuconfig) $(summary) GENCONFIG - mkdir -p $(BUILD_DIR_BASE)/include/config - cd $(BUILD_DIR_BASE); $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/conf --silentoldconfig $(IDF_PATH)/Kconfig - touch $(AUTO_CONF_REGEN_TARGET) $(BUILD_DIR_BASE)/include/sdkconfig.h -# touch to ensure both output files are newer - as 'conf' can also update sdkconfig (a dependency). Without this, -# sometimes you can get an infinite make loop on Windows where sdkconfig always gets regenerated newer -# than the target(!) +ifdef BATCH_BUILD # can't prompt for new config values like on terminal + $(call RunConf,conf --olddefconfig) +endif + $(call RunConf,conf --silentoldconfig) + touch $(SDKCONFIG_MAKEFILE) $(BUILD_DIR_BASE)/include/sdkconfig.h # ensure newer than sdkconfig -.PHONY: config-clean +else # "$(MAKE_RESTARTS)" != "" +# on subsequent make passes, skip config generation entirely +defconfig: +menuconfig: +endif + +.PHONY: config-clean defconfig menuconfig config-clean: $(summary RM CONFIG) $(MAKE) -C $(KCONFIG_TOOL_DIR) clean diff --git a/tools/kconfig/.gitignore b/tools/kconfig/.gitignore index be603c4fef..977c274ce3 100644 --- a/tools/kconfig/.gitignore +++ b/tools/kconfig/.gitignore @@ -20,3 +20,11 @@ nconf qconf gconf kxgettext + +# configuration programs, Windows +conf.exe +mconf.exe +nconf.exe +qconf.exe +gconf.exe +kxgettext.exe diff --git a/tools/kconfig/zconf.gperf b/tools/kconfig/zconf.gperf index ac498f01b4..d1ede16a80 100644 --- a/tools/kconfig/zconf.gperf +++ b/tools/kconfig/zconf.gperf @@ -9,8 +9,6 @@ struct kconf_id; -static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); - %% mainmenu, T_MAINMENU, TF_COMMAND menu, T_MENU, TF_COMMAND diff --git a/tools/unit-test-app/ModuleDefinition.yml b/tools/unit-test-app/ModuleDefinition.yml new file mode 100644 index 0000000000..0f9a31f901 --- /dev/null +++ b/tools/unit-test-app/ModuleDefinition.yml @@ -0,0 +1,127 @@ +freertos: + module: System + module abbr: SYS + sub module: OS + sub module abbr: OS +nvs: + module: System + module abbr: SYS + sub module: NVS + sub module abbr: NVS +partition: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +ulp: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +fp: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +hw: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +tjpgd: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +miniz: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +mmap: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +bignum: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +newlib: + module: System + module abbr: SYS + sub module: Std Lib + sub module abbr: STD +aes: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +mbedtls: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +spi_flash: + module: Driver + module abbr: DRV + sub module: SPI + sub module abbr: SPI +spi_flash_read: + module: Driver + module abbr: DRV + sub module: SPI + sub module abbr: SPI +spi_flash_write: + module: Driver + module abbr: DRV + sub module: SPI + sub module abbr: SPI +esp32: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +deepsleep: + module: RTC + module abbr: RTC + sub module: Deep Sleep + sub module abbr: SLEEP +sd: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +cxx: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +fatfs: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +delay: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +spi: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +vfs: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC +misc: + module: System + module abbr: SYS + sub module: Misc + sub module abbr: MISC + + diff --git a/tools/unit-test-app/UnitTestParser.py b/tools/unit-test-app/UnitTestParser.py new file mode 100644 index 0000000000..26f90a0262 --- /dev/null +++ b/tools/unit-test-app/UnitTestParser.py @@ -0,0 +1,169 @@ +import yaml +import os +import re +import sys +import shutil + + +MODULE_MAP = yaml.load(open("ModuleDefinition.yml", "r")) + +TEST_CASE_PATTERN = { + "initial condition": "UTINIT1", + "SDK": "ESP32_IDF", + "level": "Unit", + "execution time": 0, + "Test App": "UT", + "auto test": "Yes", + "category": "Function", + "test point 1": "basic function", + "version": "v1 (2016-12-06)", + "test environment": "UT_T1_1", + "expected result": "1. set succeed" +} + +CONFIG_FILE_PATTERN = { + "Config": {"execute count": 1, "execute order": "in order"}, + "DUT": [], + "Filter": [{"Add": {"ID": []}}] +} + +test_cases = list() +test_ids = {} +test_ids_by_job = {} +unit_jobs = {} + +os.chdir(os.path.join("..", "..")) +IDF_PATH = os.getcwd() + + +class Parser(object): + @classmethod + def parse_test_folders(cls): + test_folder_paths = list() + os.chdir(os.path.join(IDF_PATH, "components")) + component_dirs = os.listdir(".") + for dir in component_dirs: + os.chdir(dir) + if "test" in os.listdir("."): + test_folder_paths.append(os.path.join(os.getcwd(), "test")) + os.chdir("..") + Parser.parse_test_files(test_folder_paths) + + @classmethod + def parse_test_files(cls, test_folder_paths): + for path in test_folder_paths: + os.chdir(path) + for file_path in os.listdir("."): + if file_path[-2:] == ".c": + Parser.read_test_file(os.path.join(os.getcwd(), file_path), len(test_cases)+1) + os.chdir(os.path.join("..", "..")) + Parser.dump_test_cases(test_cases) + + @classmethod + def read_test_file(cls, test_file_path, file_index): + test_index = 0 + with open(test_file_path, "r") as file: + for line in file: + if re.match("TEST_CASE", line): + test_index += 1 + tags = re.split(r"[\[\]\"]", line) + Parser.parse_test_cases(file_index, test_index, tags) + + + @classmethod + def parse_test_cases(cls, file_index, test_index, tags): + ci_ready = "Yes" + test_env = "UT_T1_1" + for tag in tags: + if tag == "ignore": + ci_ready = "No" + if re.match("test_env=", tag): + test_env = tag[9:] + module_name = tags[4] + try: + MODULE_MAP[module_name] + except KeyError: + module_name = "misc" + id = "UT_%s_%s_%03d%02d" % (MODULE_MAP[module_name]['module abbr'], + MODULE_MAP[module_name]['sub module abbr'], + file_index, test_index) + test_case = dict(TEST_CASE_PATTERN) + test_case.update({"module": MODULE_MAP[module_name]['module'], + "CI ready": ci_ready, + "cmd set": ["IDFUnitTest/UnitTest", [tags[1]]], + "ID": id, + "test point 2": module_name, + "steps": tags[1], + "comment": tags[1], + "test environment": test_env, + "sub module": MODULE_MAP[module_name]['sub module'], + "summary": tags[1]}) + if test_case["CI ready"] == "Yes": + if test_ids.has_key(test_env): + test_ids[test_env].append(id) + else: + test_ids.update({test_env: [id]}) + test_cases.append(test_case) + + @classmethod + def dump_test_cases(cls, test_cases): + os.chdir(os.path.join(IDF_PATH, "components", "idf_test", "unit_test")) + with open ("TestCaseAll.yml", "wb+") as f: + yaml.dump({"test cases": test_cases}, f, allow_unicode=True, default_flow_style=False) + + @classmethod + def dump_ci_config(cls): + Parser.split_test_cases() + os.chdir(os.path.join(IDF_PATH, "components", "idf_test", "unit_test")) + if not os.path.exists("CIConfigs"): + os.makedirs("CIConfigs") + os.chdir("CIConfigs") + for unit_job in unit_jobs: + job = dict(CONFIG_FILE_PATTERN) + job.update({"DUT": ["UT1"]}) + job.update({"Filter": [{"Add": {"ID": test_ids_by_job[unit_job]}}]}) + with open (unit_job + ".yml", "wb+") as f: + yaml.dump(job, f, allow_unicode=True, default_flow_style=False) + + @classmethod + def split_test_cases(cls): + for job in unit_jobs: + test_ids_by_job.update({job: list()}) + for test_env in test_ids: + available_jobs = list() + for job in unit_jobs: + if test_env in unit_jobs[job]: + available_jobs.append(job) + for idx, job in enumerate(available_jobs): + test_ids_by_job[job] += (test_ids[test_env][idx*len(test_ids[test_env])/len(available_jobs):(idx+1)*len(test_ids[test_env])/len(available_jobs)]) + + @classmethod + def parse_gitlab_ci(cls): + os.chdir(IDF_PATH) + with open(".gitlab-ci.yml", "rb") as f: + gitlab_ci = yaml.load(f) + keys = gitlab_ci.keys() + for key in keys: + if re.match("UT_", key): + test_env = gitlab_ci[key]["tags"] + unit_job = key + key = {} + key.update({unit_job: test_env}) + unit_jobs.update(key) + + @classmethod + def copy_module_def_file(cls): + src = os.path.join(IDF_PATH, "tools", "unit-test-app", "ModuleDefinition.yml") + dst = os.path.join(IDF_PATH, "components", "idf_test", "unit_test") + shutil.copy(src, dst) + + +def main(): + Parser.parse_test_folders() + Parser.parse_gitlab_ci() + Parser.dump_ci_config() + Parser.copy_module_def_file() + + +if __name__ == '__main__': + main() diff --git a/tools/windows/eclipse_make.py b/tools/windows/eclipse_make.py new file mode 100644 index 0000000000..e65cfc9cc3 --- /dev/null +++ b/tools/windows/eclipse_make.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# +# Wrapper to run make and preprocess any paths in the output from MSYS/Cygwin paths +# to Windows paths, for Eclipse +from __future__ import print_function, division +import sys, subprocess, os.path, re + +UNIX_PATH_RE = re.compile(r'(/[^ \'"]+)+') + +paths = {} +def check_path(path): + try: + return paths[path] + except KeyError: + pass + paths[path] = path # cache as failed, replace with success if it works + try: + winpath = subprocess.check_output(["cygpath", "-w", path]).strip() + except subprocess.CalledProcessError: + return path # something went wrong running cygpath, assume this is not a path! + if not os.path.exists(winpath): + return path # not actually a valid path + winpath = winpath.replace("\\", "/") # make consistent with forward-slashes used elsewhere + paths[path] = winpath + return winpath + +def main(): + print("Running make in '%s'" % check_path(os.getcwd())) + make = subprocess.Popen(["make"] + sys.argv[1:] + ["BATCH_BUILD=1"], stdout=subprocess.PIPE) + for line in iter(make.stdout.readline, ''): + line = re.sub(UNIX_PATH_RE, lambda m: check_path(m.group(0)), line) + print(line.rstrip()) + sys.exit(make.wait()) + +if __name__ == "__main__": + main() diff --git a/tools/windows/eclipse_make.sh b/tools/windows/eclipse_make.sh index 200d798ffa..769bca2695 100755 --- a/tools/windows/eclipse_make.sh +++ b/tools/windows/eclipse_make.sh @@ -1,9 +1,4 @@ #!/bin/bash -# A wrapper for make on Windows with Eclipse -# -# Eclipse's output parser expects to see output of the form C:/dir/dir/file but our Make -# process uses MinGW paths of the form /c/dir/dir/file. So parse these out... -# -# (regexp deliberate only matches after a space character to try and avoid false-positives.) -echo "Running make in $(pwd)" -make $@ V=1 | sed -E "s@ /([a-z])/(.+)/@ \1:/\2/@g" | sed -E "s@-I/([a-z])/(.+)/@-I\1:/\2/@g" | sed -E "s@-L/([a-z])/(.+)/@-L\1:/\2/@g" +echo "eclipse_make.sh has been replaced with eclipse_make.py. Check the Windows Eclipse docs for the new command." +echo "This shell script will continue to work until the next major release." +python ${IDF_PATH}/tools/windows/eclipse_make.py $@