Merge branch 'master' into feature/esp32s2beta_merge

This commit is contained in:
Ivan Grokhotkov 2019-10-02 18:57:40 +02:00
commit 5830f529d8
115 changed files with 2439 additions and 622 deletions

View file

@ -1,12 +1,14 @@
name: Sync issue comments to JIRA
on: issue_comment on: issue_comment
name: Sync issue and PR comments to JIRA
jobs: jobs:
syncToJIRA: syncToJIRA:
name: Sync to JIRA name: Sync to JIRA
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Sync to JIRA - name: Sync issue comments to JIRA
uses: espressif/github-actions/sync_issues_to_jira@master uses: espressif/github-actions/sync_issues_to_jira@master
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,12 +1,14 @@
on: issues
name: Sync issues to JIRA name: Sync issues to JIRA
on: issues
jobs: jobs:
syncToJIRA: syncToJIRA:
name: Sync to JIRA name: Sync to JIRA
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Sync to JIRA - name: Sync issues to JIRA project
uses: espressif/github-actions/sync_issues_to_jira@master uses: espressif/github-actions/sync_issues_to_jira@master
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,16 +0,0 @@
on: pull_request
name: Sync PRs to JIRA
jobs:
syncToJIRA:
name: Sync to JIRA
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Sync to JIRA
uses: espressif/github-actions/sync_issues_to_jira@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JIRA_PASS: ${{ secrets.JIRA_PASS }}
JIRA_PROJECT: IDFGH
JIRA_URL: ${{ secrets.JIRA_URL }}
JIRA_USER: ${{ secrets.JIRA_USER }}

32
.github/workflows/python_lint.yml vendored Normal file
View file

@ -0,0 +1,32 @@
name: Python CI
# This workflow will be triggered when a PR modifies some python relevant files
on:
pull_request:
paths:
- "*.py"
- "requirements.txt"
jobs:
python_lint:
name: python lint
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [2.7, 3.5, 3.6, 3.7]
steps:
- name: Checkout
uses: actions/checkout@master
- name: Set up Python environment
uses: actions/setup-python@master
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
- name: Lint with flake8
run: |
pip install flake8
flake8 . --config=.flake8

View file

@ -67,7 +67,7 @@ variables:
rm -rf "$CUSTOM_TOOLCHAIN_PATH" rm -rf "$CUSTOM_TOOLCHAIN_PATH"
.setup_tools_unless_target_test: &setup_tools_unless_target_test | .setup_tools_unless_target_test: &setup_tools_unless_target_test |
if [ "$CI_JOB_STAGE" != "target_test" ]; then if [[ "$SETUP_TOOLS" == "1" || "$CI_JOB_STAGE" != "target_test" ]]; then
tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1 tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1
fi fi

View file

@ -1,7 +0,0 @@
language: python
sudo: false
python:
- "3.4"
script:
- pip install flake8
- travis_wait 20 python -m flake8 --config=.flake8 .

77
Kconfig
View file

@ -82,6 +82,83 @@ mainmenu "Espressif IoT Development Framework Configuration"
endmenu # SDK tool configuration endmenu # SDK tool configuration
menu "Build type"
choice APP_BUILD_TYPE
prompt "Application build type"
default APP_BUILD_TYPE_APP_2NDBOOT
help
Select the way the application is built.
By default, the application is built as a binary file in a format compatible with
the ESP32 bootloader. In addition to this application, 2nd stage bootloader is
also built. Application and bootloader binaries can be written into flash and
loaded/executed from there.
Another option, useful for only very small and limited applications, is to only link
the .elf file of the application, such that it can be loaded directly into RAM over
JTAG. Note that since IRAM and DRAM sizes are very limited, it is not possible to
build any complex application this way. However for kinds of testing and debugging,
this option may provide faster iterations, since the application does not need to be
written into flash.
Note that at the moment, ESP-IDF does not contain all the startup code required to
initialize the CPUs and ROM memory (data/bss). Therefore it is necessary to execute
a bit of ROM code prior to executing the application. A gdbinit file may look as follows:
# Connect to a running instance of OpenOCD
target remote :3333
# Reset and halt the target
mon reset halt
# Run to a specific point in ROM code,
# where most of initialization is complete.
thb *0x40007901
c
# Load the application into RAM
load
# Run till app_main
tb app_main
c
Execute this gdbinit file as follows:
xtensa-esp32-elf-gdb build/app-name.elf -x gdbinit
Recommended sdkconfig.defaults for building loadable ELF files is as follows.
CONFIG_APP_BUILD_TYPE_ELF_RAM is required, other options help reduce application
memory footprint.
CONFIG_APP_BUILD_TYPE_ELF_RAM=y
CONFIG_VFS_SUPPORT_TERMIOS=
CONFIG_NEWLIB_NANO_FORMAT=y
CONFIG_ESP32_PANIC_PRINT_HALT=y
CONFIG_ESP32_DEBUG_STUBS_ENABLE=
CONFIG_ESP_ERR_TO_NAME_LOOKUP=
config APP_BUILD_TYPE_APP_2NDBOOT
bool
prompt "Default (binary application + 2nd stage bootloader)"
select APP_BUILD_GENERATE_BINARIES
select APP_BUILD_BOOTLOADER
select APP_BUILD_USE_FLASH_SECTIONS
config APP_BUILD_TYPE_ELF_RAM
bool
prompt "ELF file, loadable into RAM (EXPERIMENTAL))"
endchoice # APP_BUILD_TYPE
# Hidden options, set according to the choice above
config APP_BUILD_GENERATE_BINARIES
bool # Whether to generate .bin files or not
config APP_BUILD_BOOTLOADER
bool # Whether to build the bootloader
config APP_BUILD_USE_FLASH_SECTIONS
bool # Whether to place code/data into memory-mapped flash sections
endmenu # Build type
source "$COMPONENT_KCONFIGS_PROJBUILD" source "$COMPONENT_KCONFIGS_PROJBUILD"
menu "Compiler options" menu "Compiler options"

View file

@ -1,7 +1,7 @@
idf_component_register(PRIV_REQUIRES partition_table) idf_component_register(PRIV_REQUIRES partition_table)
# Do not generate flash file when building bootloader or is in early expansion of the build # Do not generate flash file when building bootloader or is in early expansion of the build
if(BOOTLOADER_BUILD) if(BOOTLOADER_BUILD OR NOT CONFIG_APP_BUILD_BOOTLOADER)
return() return()
endif() endif()

View file

@ -391,7 +391,7 @@ menu "Security features"
config SECURE_BOOT_SIGNING_KEY config SECURE_BOOT_SIGNING_KEY
string "Secure boot private signing key" string "Secure boot private signing key"
depends on SECURE_BOOT_BUILD_SIGNED_BINARIES depends on SECURE_BOOT_BUILD_SIGNED_BINARIES
default secure_boot_signing_key.pem default "secure_boot_signing_key.pem"
help help
Path to the key file used to sign app images. Path to the key file used to sign app images.
@ -407,7 +407,7 @@ menu "Security features"
config SECURE_BOOT_VERIFICATION_KEY config SECURE_BOOT_VERIFICATION_KEY
string "Secure boot public signature verification key" string "Secure boot public signature verification key"
depends on SECURE_SIGNED_APPS && !SECURE_BOOT_BUILD_SIGNED_BINARIES depends on SECURE_SIGNED_APPS && !SECURE_BOOT_BUILD_SIGNED_BINARIES
default signature_verification_key.bin default "signature_verification_key.bin"
help help
Path to a public key file used to verify signed images. This key is compiled into the bootloader and/or Path to a public key file used to verify signed images. This key is compiled into the bootloader and/or
app, to verify app images. app, to verify app images.
@ -421,7 +421,7 @@ menu "Security features"
choice SECURE_BOOTLOADER_KEY_ENCODING choice SECURE_BOOTLOADER_KEY_ENCODING
bool "Hardware Key Encoding" bool "Hardware Key Encoding"
depends on SECURE_BOOTLOADER_REFLASHABLE depends on SECURE_BOOTLOADER_REFLASHABLE
default SECURE_BOOTLOADER_NO_ENCODING default SECURE_BOOTLOADER_KEY_ENCODING_256BIT
help help
In reflashable secure bootloader mode, a hardware key is derived from the signing key (with SHA-256) and In reflashable secure bootloader mode, a hardware key is derived from the signing key (with SHA-256) and

View file

@ -1,7 +1,7 @@
set(BOOTLOADER_OFFSET 0x1000) set(BOOTLOADER_OFFSET 0x1000)
# Do not generate flash file when building bootloader # Do not generate flash file when building bootloader
if(BOOTLOADER_BUILD) if(BOOTLOADER_BUILD OR NOT CONFIG_APP_BUILD_BOOTLOADER)
return() return()
endif() endif()

View file

@ -149,6 +149,13 @@ int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata,
*/ */
esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc); esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc);
/**
* @brief Get chip revision
*
* @return Chip revision number
*/
uint8_t bootloader_common_get_chip_revision(void);
/** /**
* @brief Check if the image (bootloader and application) has valid chip ID and revision * @brief Check if the image (bootloader and application) has valid chip ID and revision
* *

View file

@ -32,10 +32,11 @@
#include "bootloader_common.h" #include "bootloader_common.h"
#include "soc/gpio_periph.h" #include "soc/gpio_periph.h"
#include "soc/rtc.h" #include "soc/rtc.h"
#include "soc/efuse_reg.h"
#include "soc/apb_ctrl_reg.h"
#include "esp_image_format.h" #include "esp_image_format.h"
#include "bootloader_sha.h" #include "bootloader_sha.h"
#include "sys/param.h" #include "sys/param.h"
#include "esp_efuse.h"
#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */ #define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
@ -279,22 +280,50 @@ void bootloader_common_vddsdio_configure(void)
#endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST #endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
} }
#ifdef CONFIG_IDF_TARGET_ESP32
uint8_t bootloader_common_get_chip_revision(void)
{
uint8_t eco_bit0, eco_bit1, eco_bit2;
eco_bit0 = (REG_READ(EFUSE_BLK0_RDATA3_REG) & 0xF000) >> 15;
eco_bit1 = (REG_READ(EFUSE_BLK0_RDATA5_REG) & 0x100000) >> 20;
eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 0x80000000) >> 31;
uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
uint8_t chip_ver = 0;
switch (combine_value) {
case 0:
chip_ver = 0;
break;
case 1:
chip_ver = 1;
break;
case 3:
chip_ver = 2;
break;
case 7:
chip_ver = 3;
break;
default:
chip_ver = 0;
break;
}
return chip_ver;
}
#endif
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr) esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID; esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
if (chip_id != img_hdr->chip_id) { if (chip_id != img_hdr->chip_id) {
ESP_LOGE(TAG, "image has invalid chip ID, expected at least %d, found %d", chip_id, img_hdr->chip_id); ESP_LOGE(TAG, "mismatch chip ID, expect %d, found %d", chip_id, img_hdr->chip_id);
err = ESP_FAIL; err = ESP_FAIL;
} }
uint8_t revision = esp_efuse_get_chip_ver(); uint8_t revision = bootloader_common_get_chip_revision();
if (revision < img_hdr->min_chip_rev) { if (revision < img_hdr->min_chip_rev) {
ESP_LOGE(TAG, "image has invalid chip revision, expected at least %d, found %d", revision, img_hdr->min_chip_rev); ESP_LOGE(TAG, "can't run on lower chip revision, expect %d, found %d", revision, img_hdr->min_chip_rev);
err = ESP_FAIL; err = ESP_FAIL;
} else if (revision != img_hdr->min_chip_rev) { } else if (revision != img_hdr->min_chip_rev) {
ESP_LOGI(TAG, "This chip is revision %d but project was configured for minimum revision %d. "\ ESP_LOGI(TAG, "mismatch chip revision, expect %d, found %d", revision, img_hdr->min_chip_rev);
"Suggest setting project minimum revision to %d if safe to do so.",
revision, img_hdr->min_chip_rev, revision);
} }
return err; return err;
} }

View file

@ -60,7 +60,6 @@
#endif #endif
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_efuse.h"
#include "esp_image_format.h" #include "esp_image_format.h"
#include "esp_secure_boot.h" #include "esp_secure_boot.h"
#include "esp_flash_encrypt.h" #include "esp_flash_encrypt.h"
@ -171,7 +170,7 @@ static esp_err_t bootloader_main(void)
} }
/* Check chip ID and minimum chip revision that supported by this image */ /* Check chip ID and minimum chip revision that supported by this image */
uint8_t revision = esp_efuse_get_chip_ver(); uint8_t revision = bootloader_common_get_chip_revision();
ESP_LOGI(TAG, "Chip Revision: %d", revision); ESP_LOGI(TAG, "Chip Revision: %d", revision);
if (bootloader_common_check_chip_validity(&fhdr) != ESP_OK) { if (bootloader_common_check_chip_validity(&fhdr) != ESP_OK) {
return ESP_FAIL; return ESP_FAIL;

View file

@ -377,9 +377,13 @@ if(CONFIG_BT_ENABLED)
host/nimble/nimble/nimble/host/store/ram/include host/nimble/nimble/nimble/host/store/ram/include
host/nimble/nimble/nimble/host/store/config/include host/nimble/nimble/nimble/host/store/config/include
host/nimble/nimble/porting/npl/freertos/include host/nimble/nimble/porting/npl/freertos/include
host/nimble/nimble/ext/tinycrypt/include
host/nimble/esp-hci/include) host/nimble/esp-hci/include)
if(NOT CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS)
list(APPEND include_dirs
host/nimble/nimble/ext/tinycrypt/include)
list(APPEND srcs "host/nimble/nimble/ext/tinycrypt/src/utils.c" list(APPEND srcs "host/nimble/nimble/ext/tinycrypt/src/utils.c"
"host/nimble/nimble/ext/tinycrypt/src/sha256.c" "host/nimble/nimble/ext/tinycrypt/src/sha256.c"
"host/nimble/nimble/ext/tinycrypt/src/ecc.c" "host/nimble/nimble/ext/tinycrypt/src/ecc.c"
@ -394,8 +398,10 @@ if(CONFIG_BT_ENABLED)
"host/nimble/nimble/ext/tinycrypt/src/hmac_prng.c" "host/nimble/nimble/ext/tinycrypt/src/hmac_prng.c"
"host/nimble/nimble/ext/tinycrypt/src/ecc_platform_specific.c" "host/nimble/nimble/ext/tinycrypt/src/ecc_platform_specific.c"
"host/nimble/nimble/ext/tinycrypt/src/hmac.c" "host/nimble/nimble/ext/tinycrypt/src/hmac.c"
"host/nimble/nimble/ext/tinycrypt/src/cbc_mode.c" "host/nimble/nimble/ext/tinycrypt/src/cbc_mode.c")
"host/nimble/nimble/nimble/host/util/src/addr.c" endif()
list(APPEND srcs "host/nimble/nimble/nimble/host/util/src/addr.c"
"host/nimble/nimble/nimble/host/services/gatt/src/ble_svc_gatt.c" "host/nimble/nimble/nimble/host/services/gatt/src/ble_svc_gatt.c"
"host/nimble/nimble/nimble/host/services/tps/src/ble_svc_tps.c" "host/nimble/nimble/nimble/host/services/tps/src/ble_svc_tps.c"
"host/nimble/nimble/nimble/host/services/ias/src/ble_svc_ias.c" "host/nimble/nimble/nimble/host/services/ias/src/ble_svc_ias.c"

View file

@ -1,4 +1,4 @@
menu Bluetooth menu "Bluetooth"
config BT_ENABLED config BT_ENABLED
bool "Bluetooth" bool "Bluetooth"
@ -359,6 +359,21 @@ menu Bluetooth
If you set `BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it If you set `BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it
may cause adv packets lost more. may cause adv packets lost more.
menuconfig BTDM_COEX_BT_OPTIONS
bool "Coexistence Bluetooth Side Options"
depends on ESP32_WIFI_SW_COEXIST_ENABLE
default n
help
Options of Bluetooth Side of WiFi and bluetooth coexistence.
config BTDM_COEX_BLE_ADV_HIGH_PRIORITY
bool "Improve BLE ADV priority for WiFi & BLE coexistence"
depends on BTDM_COEX_BT_OPTIONS
default n
help
Improve BLE ADV coexistence priority to make it better performance.
For example, BLE mesh need to enable this option to improve BLE adv performance.
endmenu endmenu
choice BT_HOST choice BT_HOST

View file

@ -153,6 +153,7 @@ endif
ifdef CONFIG_BT_NIMBLE_ENABLED ifdef CONFIG_BT_NIMBLE_ENABLED
COMPONENT_ADD_INCLUDEDIRS += host/nimble/nimble/nimble/include \ COMPONENT_ADD_INCLUDEDIRS += host/nimble/nimble/nimble/include \
host/nimble/nimble/nimble/host/include \ host/nimble/nimble/nimble/host/include \
host/nimble/nimble/porting/nimble/include \ host/nimble/nimble/porting/nimble/include \
@ -167,14 +168,16 @@ COMPONENT_ADD_INCLUDEDIRS += host/nimble/nimble/nimble/include
host/nimble/nimble/nimble/host/util/include \ host/nimble/nimble/nimble/host/util/include \
host/nimble/nimble/nimble/host/store/ram/include \ host/nimble/nimble/nimble/host/store/ram/include \
host/nimble/nimble/nimble/host/store/config/include \ host/nimble/nimble/nimble/host/store/config/include \
host/nimble/nimble/ext/tinycrypt/include \
host/nimble/esp-hci/include \ host/nimble/esp-hci/include \
host/nimble/port/include host/nimble/port/include
ifndef CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS
COMPONENT_ADD_INCLUDEDIRS += host/nimble/nimble/ext/tinycrypt/include
endif
COMPONENT_SRCDIRS += host/nimble/nimble/nimble/host/src \ COMPONENT_SRCDIRS += host/nimble/nimble/nimble/host/src \
host/nimble/nimble/porting/nimble/src \ host/nimble/nimble/porting/nimble/src \
host/nimble/nimble/porting/npl/freertos/src \ host/nimble/nimble/porting/npl/freertos/src \
host/nimble/nimble/ext/tinycrypt/src \
host/nimble/nimble/nimble/host/services/ans/src \ host/nimble/nimble/nimble/host/services/ans/src \
host/nimble/nimble/nimble/host/services/bas/src \ host/nimble/nimble/nimble/host/services/bas/src \
host/nimble/nimble/nimble/host/services/gap/src \ host/nimble/nimble/nimble/host/services/gap/src \
@ -187,6 +190,10 @@ COMPONENT_SRCDIRS += host/nimble/nimble/nimble/host/src
host/nimble/nimble/nimble/host/store/config/src \ host/nimble/nimble/nimble/host/store/config/src \
host/nimble/esp-hci/src host/nimble/esp-hci/src
ifndef CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS
COMPONENT_SRCDIRS += host/nimble/nimble/ext/tinycrypt/src
endif
COMPONENT_OBJEXCLUDE += host/nimble/nimble/nimble/host/store/config/src/ble_store_config_conf.o COMPONENT_OBJEXCLUDE += host/nimble/nimble/nimble/host/store/config/src/ble_store_config_conf.o
ifdef CONFIG_BT_NIMBLE_MESH ifdef CONFIG_BT_NIMBLE_MESH

View file

@ -226,6 +226,7 @@ extern int coex_bt_release_wrapper(uint32_t event);
extern int coex_register_bt_cb_wrapper(coex_func_cb_t cb); extern int coex_register_bt_cb_wrapper(coex_func_cb_t cb);
extern uint32_t coex_bb_reset_lock_wrapper(void); extern uint32_t coex_bb_reset_lock_wrapper(void);
extern void coex_bb_reset_unlock_wrapper(uint32_t restore); extern void coex_bb_reset_unlock_wrapper(uint32_t restore);
extern void coex_ble_adv_priority_high_set(bool high);
extern char _bss_start_btdm; extern char _bss_start_btdm;
extern char _bss_end_btdm; extern char _bss_end_btdm;
@ -1195,6 +1196,12 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
goto error; goto error;
} }
#ifdef CONFIG_BTDM_COEX_BLE_ADV_HIGH_PRIORITY
coex_ble_adv_priority_high_set(true);
#else
coex_ble_adv_priority_high_set(false);
#endif
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
return ESP_OK; return ESP_OK;

@ -1 +1 @@
Subproject commit d122b080242fdf045bd5a8ba8b5879f2f9c7885e Subproject commit aaadbf2c26002ae85c175cb0e469a3b0bf57bf02

View file

@ -297,8 +297,6 @@ static void btc_ble_mesh_client_model_op_cb(struct bt_mesh_model *model,
struct net_buf_simple *buf) struct net_buf_simple *buf)
{ {
esp_ble_mesh_model_cb_param_t mesh_param = {0}; esp_ble_mesh_model_cb_param_t mesh_param = {0};
bt_mesh_client_user_data_t *client_param = NULL;
bt_mesh_client_internal_data_t *data = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
btc_msg_t msg = {0}; btc_msg_t msg = {0};
bt_status_t ret; bt_status_t ret;
@ -308,15 +306,11 @@ static void btc_ble_mesh_client_model_op_cb(struct bt_mesh_model *model,
return; return;
} }
client_param = (bt_mesh_client_user_data_t *)model->user_data;
data = (bt_mesh_client_internal_data_t *)client_param->internal_data;
if (!data) {
LOG_ERROR("%s, Client internal_data is NULL", __func__);
return;
}
bt_mesh_client_model_lock(); bt_mesh_client_model_lock();
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_MODEL;
node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, false); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, false);
if (node == NULL) { if (node == NULL) {
msg.act = ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT; msg.act = ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT;
@ -325,6 +319,8 @@ static void btc_ble_mesh_client_model_op_cb(struct bt_mesh_model *model,
mesh_param.client_recv_publish_msg.ctx = (esp_ble_mesh_msg_ctx_t *)ctx; mesh_param.client_recv_publish_msg.ctx = (esp_ble_mesh_msg_ctx_t *)ctx;
mesh_param.client_recv_publish_msg.length = buf->len; mesh_param.client_recv_publish_msg.length = buf->len;
mesh_param.client_recv_publish_msg.msg = buf->data; mesh_param.client_recv_publish_msg.msg = buf->data;
ret = btc_transfer_context(&msg, &mesh_param,
sizeof(esp_ble_mesh_model_cb_param_t), btc_ble_mesh_model_copy_req_data);
} else { } else {
msg.act = ESP_BLE_MESH_MODEL_OPERATION_EVT; msg.act = ESP_BLE_MESH_MODEL_OPERATION_EVT;
mesh_param.model_operation.opcode = ctx->recv_op; mesh_param.model_operation.opcode = ctx->recv_op;
@ -332,19 +328,11 @@ static void btc_ble_mesh_client_model_op_cb(struct bt_mesh_model *model,
mesh_param.model_operation.ctx = (esp_ble_mesh_msg_ctx_t *)ctx; mesh_param.model_operation.ctx = (esp_ble_mesh_msg_ctx_t *)ctx;
mesh_param.model_operation.length = buf->len; mesh_param.model_operation.length = buf->len;
mesh_param.model_operation.msg = buf->data; mesh_param.model_operation.msg = buf->data;
}
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_MODEL;
if (msg.act == ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT) {
ret = btc_transfer_context(&msg, &mesh_param,
sizeof(esp_ble_mesh_model_cb_param_t), btc_ble_mesh_model_copy_req_data);
} else {
if (!k_delayed_work_free(&node->timer)) { if (!k_delayed_work_free(&node->timer)) {
ret = btc_transfer_context(&msg, &mesh_param, ret = btc_transfer_context(&msg, &mesh_param,
sizeof(esp_ble_mesh_model_cb_param_t), btc_ble_mesh_model_copy_req_data); sizeof(esp_ble_mesh_model_cb_param_t), btc_ble_mesh_model_copy_req_data);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&data->queue, node); bt_mesh_client_free_node(node);
} else { } else {
ret = BT_STATUS_SUCCESS; ret = BT_STATUS_SUCCESS;
} }
@ -603,28 +591,18 @@ static void btc_ble_mesh_prov_register_complete_cb(int err_code)
static void btc_ble_mesh_client_model_timeout_cb(struct k_work *work) static void btc_ble_mesh_client_model_timeout_cb(struct k_work *work)
{ {
esp_ble_mesh_model_cb_param_t mesh_param = {0}; esp_ble_mesh_model_cb_param_t mesh_param = {0};
bt_mesh_client_user_data_t *client_param = NULL; struct k_delayed_work *timer = NULL;
bt_mesh_client_internal_data_t *data = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
btc_msg_t msg = {0}; btc_msg_t msg = {0};
bt_status_t ret; bt_status_t ret;
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (!node || !node->ctx.model || !node->ctx.model->user_data) {
LOG_ERROR("%s, Invalid parameter", __func__);
return;
}
client_param = (bt_mesh_client_user_data_t *)node->ctx.model->user_data;
data = (bt_mesh_client_internal_data_t *)client_param->internal_data;
if (!data) {
LOG_ERROR("%s, Client internal_data is NULL", __func__);
return;
}
bt_mesh_client_model_lock(); bt_mesh_client_model_lock();
if (!k_delayed_work_free(&node->timer)) { timer = CONTAINER_OF(work, struct k_delayed_work, work);
if (timer && !k_delayed_work_free(timer)) {
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (node) {
mesh_param.client_send_timeout.opcode = node->opcode; mesh_param.client_send_timeout.opcode = node->opcode;
mesh_param.client_send_timeout.model = (esp_ble_mesh_model_t *)node->ctx.model; mesh_param.client_send_timeout.model = (esp_ble_mesh_model_t *)node->ctx.model;
mesh_param.client_send_timeout.ctx = (esp_ble_mesh_msg_ctx_t *)&node->ctx; mesh_param.client_send_timeout.ctx = (esp_ble_mesh_msg_ctx_t *)&node->ctx;
@ -640,7 +618,8 @@ static void btc_ble_mesh_client_model_timeout_cb(struct k_work *work)
} }
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&data->queue, node); bt_mesh_client_free_node(node);
}
} }
bt_mesh_client_model_unlock(); bt_mesh_client_model_unlock();

View file

@ -386,8 +386,10 @@ static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, s8_t rssi,
void bt_mesh_adv_init(void) void bt_mesh_adv_init(void)
{ {
xBleMeshQueue = xQueueCreate(150, sizeof(bt_mesh_msg_t)); xBleMeshQueue = xQueueCreate(150, sizeof(bt_mesh_msg_t));
xTaskCreatePinnedToCore(adv_thread, "BLE_Mesh_ADV_Task", 3072, NULL, configASSERT(xBleMeshQueue);
int ret = xTaskCreatePinnedToCore(adv_thread, "BLE_Mesh_ADV_Task", 3072, NULL,
configMAX_PRIORITIES - 7, NULL, TASK_PINNED_TO_CORE); configMAX_PRIORITIES - 7, NULL, TASK_PINNED_TO_CORE);
configASSERT(ret == pdTRUE);
} }
int bt_mesh_scan_enable(void) int bt_mesh_scan_enable(void)

View file

@ -107,37 +107,23 @@ static void bt_mesh_cfg_client_unlock(void)
static void timeout_handler(struct k_work *work) static void timeout_handler(struct k_work *work)
{ {
config_internal_data_t *internal = NULL; struct k_delayed_work *timer = NULL;
bt_mesh_config_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
BT_WARN("Receive configuration status message timeout"); BT_WARN("Receive configuration status message timeout");
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (!node || !node->ctx.model) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
client = (bt_mesh_config_client_t *)node->ctx.model->user_data;
if (!client) {
BT_ERR("%s, Config Client user_data is NULL", __func__);
return;
}
internal = (config_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Config Client internal_data is NULL", __func__);
return;
}
bt_mesh_cfg_client_lock(); bt_mesh_cfg_client_lock();
if (!k_delayed_work_free(&node->timer)) { timer = CONTAINER_OF(work, struct k_delayed_work, work);
if (timer && !k_delayed_work_free(timer)) {
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (node) {
bt_mesh_config_client_cb_evt_to_btc(node->opcode, bt_mesh_config_client_cb_evt_to_btc(node->opcode,
BTC_BLE_MESH_EVT_CONFIG_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0); BTC_BLE_MESH_EVT_CONFIG_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
}
} }
bt_mesh_cfg_client_unlock(); bt_mesh_cfg_client_unlock();
@ -149,7 +135,6 @@ static void cfg_client_cancel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct bt_mesh_msg_ctx *ctx,
void *status, size_t len) void *status, size_t len)
{ {
config_internal_data_t *data = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
struct net_buf_simple buf = {0}; struct net_buf_simple buf = {0};
u8_t evt_type = 0xFF; u8_t evt_type = 0xFF;
@ -159,12 +144,6 @@ static void cfg_client_cancel(struct bt_mesh_model *model,
return; return;
} }
data = (config_internal_data_t *)cli->internal_data;
if (!data) {
BT_ERR("%s, Config Client internal_data is NULL", __func__);
return;
}
/* If it is a publish message, sent to the user directly. */ /* If it is a publish message, sent to the user directly. */
buf.data = (u8_t *)status; buf.data = (u8_t *)status;
buf.len = (u16_t)len; buf.len = (u16_t)len;
@ -235,7 +214,7 @@ static void cfg_client_cancel(struct bt_mesh_model *model,
bt_mesh_config_client_cb_evt_to_btc( bt_mesh_config_client_cb_evt_to_btc(
node->opcode, evt_type, model, ctx, (const u8_t *)status, len); node->opcode, evt_type, model, ctx, (const u8_t *)status, len);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&data->queue, node); bt_mesh_client_free_node(node);
} }
} }

View file

@ -63,37 +63,23 @@ static void bt_mesh_health_client_unlock(void)
static void timeout_handler(struct k_work *work) static void timeout_handler(struct k_work *work)
{ {
health_internal_data_t *internal = NULL; struct k_delayed_work *timer = NULL;
bt_mesh_health_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
BT_WARN("Receive health status message timeout"); BT_WARN("Receive health status message timeout");
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (!node || !node->ctx.model) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
client = (bt_mesh_health_client_t *)node->ctx.model->user_data;
if (!client) {
BT_ERR("%s, Health Client user_data is NULL", __func__);
return;
}
internal = (health_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Health Client internal_data is NULL", __func__);
return;
}
bt_mesh_health_client_lock(); bt_mesh_health_client_lock();
if (!k_delayed_work_free(&node->timer)) { timer = CONTAINER_OF(work, struct k_delayed_work, work);
if (timer && !k_delayed_work_free(timer)) {
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (node) {
bt_mesh_health_client_cb_evt_to_btc(node->opcode, bt_mesh_health_client_cb_evt_to_btc(node->opcode,
BTC_BLE_MESH_EVT_HEALTH_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0); BTC_BLE_MESH_EVT_HEALTH_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
}
} }
bt_mesh_health_client_unlock(); bt_mesh_health_client_unlock();
@ -105,7 +91,6 @@ static void health_client_cancel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct bt_mesh_msg_ctx *ctx,
void *status, size_t len) void *status, size_t len)
{ {
health_internal_data_t *data = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
struct net_buf_simple buf = {0}; struct net_buf_simple buf = {0};
u8_t evt_type = 0xFF; u8_t evt_type = 0xFF;
@ -115,12 +100,6 @@ static void health_client_cancel(struct bt_mesh_model *model,
return; return;
} }
data = (health_internal_data_t *)health_cli->internal_data;
if (!data) {
BT_ERR("%s, Health Client internal_data is NULL", __func__);
return;
}
/* If it is a publish message, sent to the user directly. */ /* If it is a publish message, sent to the user directly. */
buf.data = (u8_t *)status; buf.data = (u8_t *)status;
buf.len = (u16_t)len; buf.len = (u16_t)len;
@ -151,7 +130,7 @@ static void health_client_cancel(struct bt_mesh_model *model,
bt_mesh_health_client_cb_evt_to_btc( bt_mesh_health_client_cb_evt_to_btc(
node->opcode, evt_type, model, ctx, (const u8_t *)status, len); node->opcode, evt_type, model, ctx, (const u8_t *)status, len);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&data->queue, node); bt_mesh_client_free_node(node);
} }
} }

View file

@ -103,7 +103,7 @@ void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler)
osi_mutex_lock(&bm_alarm_lock, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&bm_alarm_lock, OSI_MUTEX_MAX_TIMEOUT);
if (!hash_map_has_key(bm_alarm_hash_map, (void *)work)) { if (!hash_map_has_key(bm_alarm_hash_map, (void *)work)) {
alarm = osi_alarm_new("bt_mesh", (osi_alarm_callback_t)handler, (void *)work, 0); alarm = osi_alarm_new("bt_mesh", (osi_alarm_callback_t)handler, (void *)&work->work, 0);
if (alarm == NULL) { if (alarm == NULL) {
BT_ERR("%s, Unable to create alarm", __func__); BT_ERR("%s, Unable to create alarm", __func__);
return; return;

View file

@ -284,15 +284,30 @@ int bt_mesh_client_init(struct bt_mesh_model *model)
return 0; return 0;
} }
int bt_mesh_client_free_node(sys_slist_t *queue, bt_mesh_client_node_t *node) int bt_mesh_client_free_node(bt_mesh_client_node_t *node)
{ {
if (!queue || !node) { bt_mesh_client_internal_data_t *internal = NULL;
BT_ERR("%s, Invalid parameter", __func__); bt_mesh_client_user_data_t *client = NULL;
if (!node || !node->ctx.model) {
BT_ERR("%s, Client model list item is NULL", __func__);
return -EINVAL;
}
client = (bt_mesh_client_user_data_t *)node->ctx.model->user_data;
if (!client) {
BT_ERR("%s, Client model user data is NULL", __func__);
return -EINVAL;
}
internal = (bt_mesh_client_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Client model internal data is NULL", __func__);
return -EINVAL; return -EINVAL;
} }
// Release the client node from the queue // Release the client node from the queue
sys_slist_find_and_remove(queue, &node->client_node); sys_slist_find_and_remove(&internal->queue, &node->client_node);
// Free the node // Free the node
osi_free(node); osi_free(node);

View file

@ -144,37 +144,23 @@ static void bt_mesh_generic_client_unlock(void)
static void timeout_handler(struct k_work *work) static void timeout_handler(struct k_work *work)
{ {
generic_internal_data_t *internal = NULL; struct k_delayed_work *timer = NULL;
bt_mesh_generic_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
BT_WARN("Receive generic status message timeout"); BT_WARN("Receive generic status message timeout");
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (!node || !node->ctx.model) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
client = (bt_mesh_generic_client_t *)node->ctx.model->user_data;
if (!client) {
BT_ERR("%s, Generic Client user_data is NULL", __func__);
return;
}
internal = (generic_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Generic Client internal_data is NULL", __func__);
return;
}
bt_mesh_generic_client_lock(); bt_mesh_generic_client_lock();
if (!k_delayed_work_free(&node->timer)) { timer = CONTAINER_OF(work, struct k_delayed_work, work);
if (timer && !k_delayed_work_free(timer)) {
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (node) {
bt_mesh_generic_client_cb_evt_to_btc(node->opcode, bt_mesh_generic_client_cb_evt_to_btc(node->opcode,
BTC_BLE_MESH_EVT_GENERIC_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0); BTC_BLE_MESH_EVT_GENERIC_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
}
} }
bt_mesh_generic_client_unlock(); bt_mesh_generic_client_unlock();
@ -186,31 +172,14 @@ static void generic_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf) struct net_buf_simple *buf)
{ {
generic_internal_data_t *internal = NULL;
bt_mesh_generic_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
u8_t *val = NULL; u8_t *val = NULL;
u8_t evt = 0xFF; u8_t evt = 0xFF;
u32_t rsp = 0;
size_t len = 0; size_t len = 0;
BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len)); BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len));
client = (bt_mesh_generic_client_t *)model->user_data; switch (ctx->recv_op) {
if (!client) {
BT_ERR("%s, Generic Client user_data is NULL", __func__);
return;
}
internal = (generic_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Generic Client internal_data is NULL", __func__);
return;
}
rsp = ctx->recv_op;
switch (rsp) {
case BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS: { case BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS: {
struct bt_mesh_gen_onoff_status *status = NULL; struct bt_mesh_gen_onoff_status *status = NULL;
if (buf->len != 1 && buf->len != 3) { if (buf->len != 1 && buf->len != 3) {
@ -569,7 +538,7 @@ static void generic_status(struct bt_mesh_model *model,
node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true);
if (!node) { if (!node) {
BT_DBG("Unexpected generic status message 0x%x", rsp); BT_DBG("Unexpected generic status message 0x%x", ctx->recv_op);
} else { } else {
switch (node->opcode) { switch (node->opcode) {
case BLE_MESH_MODEL_OP_GEN_ONOFF_GET: case BLE_MESH_MODEL_OP_GEN_ONOFF_GET:
@ -615,13 +584,13 @@ static void generic_status(struct bt_mesh_model *model,
if (!k_delayed_work_free(&node->timer)) { if (!k_delayed_work_free(&node->timer)) {
bt_mesh_generic_client_cb_evt_to_btc(node->opcode, evt, model, ctx, val, len); bt_mesh_generic_client_cb_evt_to_btc(node->opcode, evt, model, ctx, val, len);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
} }
} }
bt_mesh_generic_client_unlock(); bt_mesh_generic_client_unlock();
switch (rsp) { switch (ctx->recv_op) {
case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: { case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: {
struct bt_mesh_gen_user_properties_status *status; struct bt_mesh_gen_user_properties_status *status;
status = (struct bt_mesh_gen_user_properties_status *)val; status = (struct bt_mesh_gen_user_properties_status *)val;

View file

@ -112,7 +112,7 @@ int bt_mesh_client_send_msg(struct bt_mesh_model *model,
s32_t timeout, bool need_ack, s32_t timeout, bool need_ack,
const struct bt_mesh_send_cb *cb, void *cb_data); const struct bt_mesh_send_cb *cb, void *cb_data);
int bt_mesh_client_free_node(sys_slist_t *queue, bt_mesh_client_node_t *node); int bt_mesh_client_free_node(bt_mesh_client_node_t *node);
enum { enum {
NODE = 0, NODE = 0,

View file

@ -153,37 +153,23 @@ static void bt_mesh_light_client_unlock(void)
static void timeout_handler(struct k_work *work) static void timeout_handler(struct k_work *work)
{ {
light_internal_data_t *internal = NULL; struct k_delayed_work *timer = NULL;
bt_mesh_light_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
BT_WARN("Receive light status message timeout"); BT_WARN("Receive light status message timeout");
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (!node || !node->ctx.model) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
client = (bt_mesh_light_client_t *)node->ctx.model->user_data;
if (!client) {
BT_ERR("%s, Lighting Client user_data is NULL", __func__);
return;
}
internal = (light_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Lighting Client internal_data is NULL", __func__);
return;
}
bt_mesh_light_client_lock(); bt_mesh_light_client_lock();
if (!k_delayed_work_free(&node->timer)) { timer = CONTAINER_OF(work, struct k_delayed_work, work);
if (timer && !k_delayed_work_free(timer)) {
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (node) {
bt_mesh_lighting_client_cb_evt_to_btc(node->opcode, bt_mesh_lighting_client_cb_evt_to_btc(node->opcode,
BTC_BLE_MESH_EVT_LIGHTING_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0); BTC_BLE_MESH_EVT_LIGHTING_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
}
} }
bt_mesh_light_client_unlock(); bt_mesh_light_client_unlock();
@ -195,31 +181,14 @@ static void light_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf) struct net_buf_simple *buf)
{ {
light_internal_data_t *internal = NULL;
bt_mesh_light_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
u8_t *val = NULL; u8_t *val = NULL;
u8_t evt = 0xFF; u8_t evt = 0xFF;
u32_t rsp = 0;
size_t len = 0; size_t len = 0;
BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len)); BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len));
client = (bt_mesh_light_client_t *)model->user_data; switch (ctx->recv_op) {
if (!client) {
BT_ERR("%s, Lighting Client user_data is NULL", __func__);
return;
}
internal = (light_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Lighting Client internal_data is NULL", __func__);
return;
}
rsp = ctx->recv_op;
switch (rsp) {
case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS: { case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS: {
struct bt_mesh_light_lightness_status *status = NULL; struct bt_mesh_light_lightness_status *status = NULL;
if (buf->len != 2 && buf->len != 5) { if (buf->len != 2 && buf->len != 5) {
@ -684,7 +653,7 @@ static void light_status(struct bt_mesh_model *model,
node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true);
if (!node) { if (!node) {
BT_DBG("Unexpected light status message 0x%x", rsp); BT_DBG("Unexpected light status message 0x%x", ctx->recv_op);
} else { } else {
switch (node->opcode) { switch (node->opcode) {
case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET: case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET:
@ -741,13 +710,13 @@ static void light_status(struct bt_mesh_model *model,
if (!k_delayed_work_free(&node->timer)) { if (!k_delayed_work_free(&node->timer)) {
bt_mesh_lighting_client_cb_evt_to_btc(node->opcode, evt, model, ctx, val, len); bt_mesh_lighting_client_cb_evt_to_btc(node->opcode, evt, model, ctx, val, len);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
} }
} }
bt_mesh_light_client_unlock(); bt_mesh_light_client_unlock();
switch (rsp) { switch (ctx->recv_op) {
case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: { case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: {
struct bt_mesh_light_lc_property_status *status; struct bt_mesh_light_lc_property_status *status;
status = (struct bt_mesh_light_lc_property_status *)val; status = (struct bt_mesh_light_lc_property_status *)val;

View file

@ -82,37 +82,23 @@ static void bt_mesh_sensor_client_unlock(void)
static void timeout_handler(struct k_work *work) static void timeout_handler(struct k_work *work)
{ {
sensor_internal_data_t *internal = NULL; struct k_delayed_work *timer = NULL;
bt_mesh_sensor_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
BT_WARN("Receive sensor status message timeout"); BT_WARN("Receive sensor status message timeout");
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (!node || !node->ctx.model) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
client = (bt_mesh_sensor_client_t *)node->ctx.model->user_data;
if (!client) {
BT_ERR("%s, Sensor Client user_data is NULL", __func__);
return;
}
internal = (sensor_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Sensor Client internal_data is NULL", __func__);
return;
}
bt_mesh_sensor_client_lock(); bt_mesh_sensor_client_lock();
if (!k_delayed_work_free(&node->timer)) { timer = CONTAINER_OF(work, struct k_delayed_work, work);
if (timer && !k_delayed_work_free(timer)) {
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (node) {
bt_mesh_sensor_client_cb_evt_to_btc(node->opcode, bt_mesh_sensor_client_cb_evt_to_btc(node->opcode,
BTC_BLE_MESH_EVT_SENSOR_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0); BTC_BLE_MESH_EVT_SENSOR_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
}
} }
bt_mesh_sensor_client_unlock(); bt_mesh_sensor_client_unlock();
@ -124,30 +110,14 @@ static void sensor_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf) struct net_buf_simple *buf)
{ {
sensor_internal_data_t *internal = NULL;
bt_mesh_sensor_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
u8_t *val = NULL; u8_t *val = NULL;
u8_t evt = 0xFF; u8_t evt = 0xFF;
u32_t rsp = 0;
size_t len = 0; size_t len = 0;
BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len)); BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len));
client = (bt_mesh_sensor_client_t *)model->user_data; switch (ctx->recv_op) {
if (!client) {
BT_ERR("%s, Sensor Client user_data is NULL", __func__);
return;
}
internal = (sensor_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Sensor Client internal_data is NULL", __func__);
return;
}
rsp = ctx->recv_op;
switch (rsp) {
case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: { case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: {
struct bt_mesh_sensor_descriptor_status *status = NULL; struct bt_mesh_sensor_descriptor_status *status = NULL;
status = osi_calloc(sizeof(struct bt_mesh_sensor_descriptor_status)); status = osi_calloc(sizeof(struct bt_mesh_sensor_descriptor_status));
@ -296,7 +266,7 @@ static void sensor_status(struct bt_mesh_model *model,
node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true);
if (!node) { if (!node) {
BT_DBG("Unexpected sensor status message 0x%x", rsp); BT_DBG("Unexpected sensor status message 0x%x", ctx->recv_op);
} else { } else {
switch (node->opcode) { switch (node->opcode) {
case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET:
@ -319,13 +289,13 @@ static void sensor_status(struct bt_mesh_model *model,
if (!k_delayed_work_free(&node->timer)) { if (!k_delayed_work_free(&node->timer)) {
bt_mesh_sensor_client_cb_evt_to_btc(node->opcode, evt, model, ctx, val, len); bt_mesh_sensor_client_cb_evt_to_btc(node->opcode, evt, model, ctx, val, len);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
} }
} }
bt_mesh_sensor_client_unlock(); bt_mesh_sensor_client_unlock();
switch (rsp) { switch (ctx->recv_op) {
case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: { case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: {
struct bt_mesh_sensor_descriptor_status *status; struct bt_mesh_sensor_descriptor_status *status;
status = (struct bt_mesh_sensor_descriptor_status *)val; status = (struct bt_mesh_sensor_descriptor_status *)val;

View file

@ -98,37 +98,23 @@ static void bt_mesh_time_scene_client_unlock(void)
static void timeout_handler(struct k_work *work) static void timeout_handler(struct k_work *work)
{ {
time_scene_internal_data_t *internal = NULL; struct k_delayed_work *timer = NULL;
bt_mesh_time_scene_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
BT_WARN("Receive time scene status message timeout"); BT_WARN("Receive time scene status message timeout");
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (!node || !node->ctx.model) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
client = (bt_mesh_time_scene_client_t *)node->ctx.model->user_data;
if (!client) {
BT_ERR("%s, Time Scene Client user_data is NULL", __func__);
return;
}
internal = (time_scene_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Time Scene Client internal_data is NULL", __func__);
return;
}
bt_mesh_time_scene_client_lock(); bt_mesh_time_scene_client_lock();
if (!k_delayed_work_free(&node->timer)) { timer = CONTAINER_OF(work, struct k_delayed_work, work);
if (timer && !k_delayed_work_free(timer)) {
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (node) {
bt_mesh_time_scene_client_cb_evt_to_btc(node->opcode, bt_mesh_time_scene_client_cb_evt_to_btc(node->opcode,
BTC_BLE_MESH_EVT_TIME_SCENE_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0); BTC_BLE_MESH_EVT_TIME_SCENE_CLIENT_TIMEOUT, node->ctx.model, &node->ctx, NULL, 0);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
}
} }
bt_mesh_time_scene_client_unlock(); bt_mesh_time_scene_client_unlock();
@ -140,30 +126,14 @@ static void time_scene_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf) struct net_buf_simple *buf)
{ {
time_scene_internal_data_t *internal = NULL;
bt_mesh_time_scene_client_t *client = NULL;
bt_mesh_client_node_t *node = NULL; bt_mesh_client_node_t *node = NULL;
u8_t *val = NULL; u8_t *val = NULL;
u8_t evt = 0xFF; u8_t evt = 0xFF;
u32_t rsp = 0;
size_t len = 0; size_t len = 0;
BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len)); BT_DBG("%s, len %d, bytes %s", __func__, buf->len, bt_hex(buf->data, buf->len));
client = (bt_mesh_time_scene_client_t *)model->user_data; switch (ctx->recv_op) {
if (!client) {
BT_ERR("%s, Time Scene Client user_data is NULL", __func__);
return;
}
internal = (time_scene_internal_data_t *)client->internal_data;
if (!internal) {
BT_ERR("%s, Time Scene Client internal_data is NULL", __func__);
return;
}
rsp = ctx->recv_op;
switch (rsp) {
case BLE_MESH_MODEL_OP_TIME_STATUS: { case BLE_MESH_MODEL_OP_TIME_STATUS: {
struct bt_mesh_time_status *status = NULL; struct bt_mesh_time_status *status = NULL;
if (buf->len != 5 && buf->len != 10) { if (buf->len != 5 && buf->len != 10) {
@ -333,7 +303,7 @@ static void time_scene_status(struct bt_mesh_model *model,
node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true);
if (!node) { if (!node) {
BT_DBG("Unexpected time scene status message 0x%x", rsp); BT_DBG("Unexpected time scene status message 0x%x", ctx->recv_op);
} else { } else {
switch (node->opcode) { switch (node->opcode) {
case BLE_MESH_MODEL_OP_TIME_GET: case BLE_MESH_MODEL_OP_TIME_GET:
@ -363,13 +333,13 @@ static void time_scene_status(struct bt_mesh_model *model,
if (!k_delayed_work_free(&node->timer)) { if (!k_delayed_work_free(&node->timer)) {
bt_mesh_time_scene_client_cb_evt_to_btc(node->opcode, evt, model, ctx, val, len); bt_mesh_time_scene_client_cb_evt_to_btc(node->opcode, evt, model, ctx, val, len);
// Don't forget to release the node at the end. // Don't forget to release the node at the end.
bt_mesh_client_free_node(&internal->queue, node); bt_mesh_client_free_node(node);
} }
} }
bt_mesh_time_scene_client_unlock(); bt_mesh_time_scene_client_unlock();
switch (rsp) { switch (ctx->recv_op) {
case BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: { case BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: {
struct bt_mesh_scene_register_status *status; struct bt_mesh_scene_register_status *status;
status = (struct bt_mesh_scene_register_status *)val; status = (struct bt_mesh_scene_register_status *)val;

View file

@ -267,14 +267,25 @@ typedef enum {
typedef enum { typedef enum {
ESP_BLE_SM_PASSKEY = 0, ESP_BLE_SM_PASSKEY = 0,
/* Authentication requirements of local device */
ESP_BLE_SM_AUTHEN_REQ_MODE, ESP_BLE_SM_AUTHEN_REQ_MODE,
/* The IO capability of local device */
ESP_BLE_SM_IOCAP_MODE, ESP_BLE_SM_IOCAP_MODE,
/* Initiator Key Distribution/Generation */
ESP_BLE_SM_SET_INIT_KEY, ESP_BLE_SM_SET_INIT_KEY,
/* Responder Key Distribution/Generation */
ESP_BLE_SM_SET_RSP_KEY, ESP_BLE_SM_SET_RSP_KEY,
/* Maximum Encryption key size to support */
ESP_BLE_SM_MAX_KEY_SIZE, ESP_BLE_SM_MAX_KEY_SIZE,
/* Minimum Encryption key size requirement from Peer */
ESP_BLE_SM_MIN_KEY_SIZE,
/* Set static Passkey */
ESP_BLE_SM_SET_STATIC_PASSKEY, ESP_BLE_SM_SET_STATIC_PASSKEY,
/* Reset static Passkey */
ESP_BLE_SM_CLEAR_STATIC_PASSKEY, ESP_BLE_SM_CLEAR_STATIC_PASSKEY,
/* Accept only specified SMP Authentication requirement */
ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH,
/* Enable/Disable OOB support */
ESP_BLE_SM_OOB_SUPPORT, ESP_BLE_SM_OOB_SUPPORT,
ESP_BLE_SM_MAX_PARAM, ESP_BLE_SM_MAX_PARAM,
} esp_ble_sm_param_t; } esp_ble_sm_param_t;

View file

@ -48,6 +48,7 @@ tBTE_APPL_CFG bte_appl_cfg = {
BTM_BLE_INITIATOR_KEY_SIZE, BTM_BLE_INITIATOR_KEY_SIZE,
BTM_BLE_RESPONDER_KEY_SIZE, BTM_BLE_RESPONDER_KEY_SIZE,
BTM_BLE_MAX_KEY_SIZE, BTM_BLE_MAX_KEY_SIZE,
BTM_BLE_MIN_KEY_SIZE,
BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE, BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE,
BTM_BLE_OOB_DISABLE, BTM_BLE_OOB_DISABLE,
}; };
@ -407,7 +408,7 @@ void bta_dm_co_ble_set_rsp_key_req(UINT8 rsp_key)
void bta_dm_co_ble_set_max_key_size(UINT8 ble_key_size) void bta_dm_co_ble_set_max_key_size(UINT8 ble_key_size)
{ {
#if (SMP_INCLUDED == TRUE) #if (SMP_INCLUDED == TRUE)
if(ble_key_size >= BTM_BLE_MIN_KEY_SIZE && ble_key_size <= BTM_BLE_MAX_KEY_SIZE) { if(ble_key_size >= bte_appl_cfg.ble_min_key_size && ble_key_size <= BTM_BLE_MAX_KEY_SIZE) {
bte_appl_cfg.ble_max_key_size = ble_key_size; bte_appl_cfg.ble_max_key_size = ble_key_size;
} else { } else {
APPL_TRACE_ERROR("%s error:Invalid key size value, key_size =%d",__func__, ble_key_size); APPL_TRACE_ERROR("%s error:Invalid key size value, key_size =%d",__func__, ble_key_size);
@ -415,6 +416,17 @@ void bta_dm_co_ble_set_max_key_size(UINT8 ble_key_size)
#endif ///SMP_INCLUDED == TRUE #endif ///SMP_INCLUDED == TRUE
} }
void bta_dm_co_ble_set_min_key_size(UINT8 ble_key_size)
{
#if (SMP_INCLUDED == TRUE)
if(ble_key_size >= BTM_BLE_MIN_KEY_SIZE && ble_key_size <= bte_appl_cfg.ble_max_key_size) {
bte_appl_cfg.ble_min_key_size = ble_key_size;
} else {
APPL_TRACE_ERROR("%s error:Invalid key size value, key_size =%d",__func__, ble_key_size);
}
#endif ///SMP_INCLUDED == TRUE
}
void bta_dm_co_ble_set_accept_auth_enable(UINT8 enable) void bta_dm_co_ble_set_accept_auth_enable(UINT8 enable)
{ {
#if (SMP_INCLUDED == TRUE) #if (SMP_INCLUDED == TRUE)

View file

@ -206,6 +206,8 @@ extern void bta_dm_co_ble_set_rsp_key_req(UINT8 rsp_key);
extern void bta_dm_co_ble_set_max_key_size(UINT8 ble_key_size); extern void bta_dm_co_ble_set_max_key_size(UINT8 ble_key_size);
extern void bta_dm_co_ble_set_min_key_size(UINT8 ble_key_size);
extern void bta_dm_co_ble_set_accept_auth_enable(UINT8 enable); extern void bta_dm_co_ble_set_accept_auth_enable(UINT8 enable);
extern UINT8 bta_dm_co_ble_get_accept_auth_enable(void); extern UINT8 bta_dm_co_ble_get_accept_auth_enable(void);

View file

@ -1196,6 +1196,12 @@ void btc_gap_ble_call_handler(btc_msg_t *msg)
bta_dm_co_ble_set_max_key_size(key_size); bta_dm_co_ble_set_max_key_size(key_size);
break; break;
} }
case ESP_BLE_SM_MIN_KEY_SIZE: {
uint8_t key_size = 0;
STREAM_TO_UINT8(key_size, value);
bta_dm_co_ble_set_min_key_size(key_size);
break;
}
case ESP_BLE_SM_SET_STATIC_PASSKEY: { case ESP_BLE_SM_SET_STATIC_PASSKEY: {
uint32_t passkey = 0; uint32_t passkey = 0;
for(uint8_t i = 0; i < arg->set_security_param.len; i++) for(uint8_t i = 0; i < arg->set_security_param.len; i++)

View file

@ -31,6 +31,7 @@ typedef struct {
UINT8 ble_init_key; UINT8 ble_init_key;
UINT8 ble_resp_key; UINT8 ble_resp_key;
UINT8 ble_max_key_size; UINT8 ble_max_key_size;
UINT8 ble_min_key_size;
UINT8 ble_accept_auth_enable; UINT8 ble_accept_auth_enable;
UINT8 oob_support; UINT8 oob_support;
#endif #endif

View file

@ -36,6 +36,7 @@
#include "smp_int.h" #include "smp_int.h"
#include "device/controller.h" #include "device/controller.h"
#include "btm_int.h" #include "btm_int.h"
#include "common/bte_appl.h"
#define SMP_PAIRING_REQ_SIZE 7 #define SMP_PAIRING_REQ_SIZE 7
#define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1) #define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1)
@ -1140,9 +1141,27 @@ BOOLEAN smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb)
return FALSE; return FALSE;
} }
if ((enc_size < SMP_ENCR_KEY_SIZE_MIN) || (enc_size > SMP_ENCR_KEY_SIZE_MAX)) { /* `bte_appl_cfg.ble_min_enc_key_size` will be `SMP_ENCR_KEY_SIZE_MIN` by
* default if not set explicitly */
#if (BLE_INCLUDED == TRUE)
if (enc_size < bte_appl_cfg.ble_min_key_size) {
SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \
Key value (0x%02x) out of range).\n", Key value (0x%02x) less than minimum required key size).\n",
p_cb->rcvd_cmd_code, enc_size);
return FALSE;
}
#else
if (enc_size < SMP_ENCR_KEY_SIZE_MIN) {
SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \
Key value (0x%02x) less than minimum required key size).\n",
p_cb->rcvd_cmd_code, enc_size);
return FALSE;
}
#endif
if (enc_size > SMP_ENCR_KEY_SIZE_MAX) {
SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \
Key value (0x%02x) greater than supported by stack).\n",
p_cb->rcvd_cmd_code, enc_size); p_cb->rcvd_cmd_code, enc_size);
return FALSE; return FALSE;
} }

View file

@ -99,11 +99,11 @@ config BT_NIMBLE_SM_SC
Enable security manager secure connections Enable security manager secure connections
config BT_NIMBLE_DEBUG config BT_NIMBLE_DEBUG
bool "Enable host debugging" bool "Enable extra runtime asserts and host debugging"
default n default n
depends on BT_NIMBLE_ENABLED depends on BT_NIMBLE_ENABLED
help help
This enables extra runtime assertions This enables extra runtime asserts and host debugging
config BT_NIMBLE_SVC_GAP_DEVICE_NAME config BT_NIMBLE_SVC_GAP_DEVICE_NAME
string "BLE GAP default device name" string "BLE GAP default device name"
@ -257,3 +257,12 @@ config BT_NIMBLE_MESH_DEVICE_NAME
help help
This value defines Bluetooth Mesh device/node name This value defines Bluetooth Mesh device/node name
config BT_NIMBLE_CRYPTO_STACK_MBEDTLS
bool "Override TinyCrypt with mbedTLS for crypto computations"
default y
depends on BT_NIMBLE_ENABLED
select MBEDTLS_ECP_RESTARTABLE
select MBEDTLS_CMAC_C
help
Enable this option to choose mbedTLS instead of TinyCrypt for crypto
computations.

@ -1 +1 @@
Subproject commit adcd9408695cb4f873f117eb8c92007455b2c066 Subproject commit 6c91a9a153c421231b686d30c822e53fea7510c0

View file

@ -567,6 +567,10 @@
#define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0)
#endif #endif
#ifndef MYNEWT_VAL_BLE_CRYPTO_STACK_MBEDTLS
#define MYNEWT_VAL_BLE_CRYPTO_STACK_MBEDTLS (CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS)
#endif
#ifndef MYNEWT_VAL_BLE_STORE_MAX_BONDS #ifndef MYNEWT_VAL_BLE_STORE_MAX_BONDS
#define MYNEWT_VAL_BLE_STORE_MAX_BONDS CONFIG_BT_NIMBLE_MAX_BONDS #define MYNEWT_VAL_BLE_STORE_MAX_BONDS CONFIG_BT_NIMBLE_MAX_BONDS
#endif #endif

View file

@ -1,9 +1,17 @@
idf_component_register(SRCS "cxx_exception_stubs.cpp" idf_component_register(SRCS "cxx_exception_stubs.cpp"
"cxx_guards.cpp") "cxx_guards.cpp"
# Make sure that pthread is in component list
PRIV_REQUIRES pthread)
target_link_libraries(${COMPONENT_LIB} PUBLIC stdc++ gcc) target_link_libraries(${COMPONENT_LIB} PUBLIC stdc++ gcc)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxa_guard_dummy") target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxa_guard_dummy")
# Force pthread to also appear later than stdc++ in link line
add_library(stdcpp_pthread INTERFACE)
idf_component_get_property(pthread pthread COMPONENT_LIB)
target_link_libraries(stdcpp_pthread INTERFACE stdc++ $<TARGET_FILE:${pthread}>)
target_link_libraries(${COMPONENT_LIB} PUBLIC stdcpp_pthread)
if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS) if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxx_fatal_exception") target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxx_fatal_exception")
endif() endif()

View file

@ -9,7 +9,7 @@ menu "eFuse Bit Manager"
config EFUSE_CUSTOM_TABLE_FILENAME config EFUSE_CUSTOM_TABLE_FILENAME
string "Custom eFuse CSV file" string "Custom eFuse CSV file"
depends on EFUSE_CUSTOM_TABLE depends on EFUSE_CUSTOM_TABLE
default main/esp_efuse_custom_table.csv default "main/esp_efuse_custom_table.csv"
help help
Name of the custom eFuse CSV filename. This path is evaluated Name of the custom eFuse CSV filename. This path is evaluated
relative to the project root directory. relative to the project root directory.

View file

@ -36,7 +36,7 @@ uint8_t esp_efuse_get_chip_ver(void)
uint8_t eco_bit0, eco_bit1, eco_bit2; uint8_t eco_bit0, eco_bit1, eco_bit2;
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &eco_bit0, 1); esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &eco_bit0, 1);
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV2, &eco_bit1, 1); esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV2, &eco_bit1, 1);
eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 80000000) >> 31; eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 0x80000000) >> 31;
uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0; uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
uint8_t chip_ver = 0; uint8_t chip_ver = 0;
switch (combine_value) { switch (combine_value) {

View file

@ -89,7 +89,7 @@ menu "ESP32-specific"
choice SPIRAM_SPEED choice SPIRAM_SPEED
prompt "Set RAM clock speed" prompt "Set RAM clock speed"
default SPIRAM_CACHE_SPEED_40M default SPIRAM_SPEED_40M
help help
Select the speed for the SPI RAM chip. Select the speed for the SPI RAM chip.
If SPI RAM is enabled, we only support three combinations of SPI speed mode we supported now: If SPI RAM is enabled, we only support three combinations of SPI speed mode we supported now:
@ -402,7 +402,7 @@ menu "ESP32-specific"
choice ESP32_BROWNOUT_DET_LVL_SEL choice ESP32_BROWNOUT_DET_LVL_SEL
prompt "Brownout voltage level" prompt "Brownout voltage level"
depends on ESP32_BROWNOUT_DET depends on ESP32_BROWNOUT_DET
default BROWNOUT_DET_LVL_SEL_25 default ESP32_BROWNOUT_DET_LVL_SEL_0
help help
The brownout detector will reset the chip when the supply voltage is approximately The brownout detector will reset the chip when the supply voltage is approximately
below this level. Note that there may be some variation of brownout voltage level below this level. Note that there may be some variation of brownout voltage level
@ -653,6 +653,11 @@ menu "ESP32-specific"
Enabling this setting adds approximately 1KB to the app's IRAM usage. Enabling this setting adds approximately 1KB to the app's IRAM usage.
config ESP32_APP_INIT_CLK
bool
default y if ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS
default y if APP_BUILD_TYPE_ELF_RAM
config ESP32_RTCDATA_IN_FAST_MEM config ESP32_RTCDATA_IN_FAST_MEM
bool "Place RTC_DATA_ATTR and RTC_RODATA_ATTR variables into RTC fast memory segment" bool "Place RTC_DATA_ATTR and RTC_RODATA_ATTR variables into RTC fast memory segment"
default n default n

View file

@ -75,7 +75,7 @@ void esp_clk_init(void)
rtc_config_t cfg = RTC_CONFIG_DEFAULT(); rtc_config_t cfg = RTC_CONFIG_DEFAULT();
rtc_init(cfg); rtc_init(cfg);
#ifdef CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS #if (CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS || CONFIG_ESP32_APP_INIT_CLK)
/* Check the bootloader set the XTAL frequency. /* Check the bootloader set the XTAL frequency.
Bootloaders pre-v2.1 don't do this. Bootloaders pre-v2.1 don't do this.
@ -293,6 +293,8 @@ void esp_perip_clk_init(void)
DPORT_I2S1_CLK_EN | DPORT_I2S1_CLK_EN |
DPORT_SPI_DMA_CLK_EN; DPORT_SPI_DMA_CLK_EN;
common_perip_clk &= ~DPORT_SPI01_CLK_EN;
#if CONFIG_SPIRAM_SPEED_80M #if CONFIG_SPIRAM_SPEED_80M
//80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in //80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in
//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs' //a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs'

View file

@ -72,6 +72,11 @@
#include "esp_efuse.h" #include "esp_efuse.h"
#include "bootloader_flash_config.h" #include "bootloader_flash_config.h"
#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM
#include "esp32/rom/efuse.h"
#include "esp32/rom/spi_flash.h"
#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM
#define STRINGIFY(s) STRINGIFY2(s) #define STRINGIFY(s) STRINGIFY2(s)
#define STRINGIFY2(s) #s #define STRINGIFY2(s) #s
@ -391,6 +396,32 @@ void start_cpu0_default(void)
#ifndef CONFIG_FREERTOS_UNICORE #ifndef CONFIG_FREERTOS_UNICORE
esp_dport_access_int_init(); esp_dport_access_int_init();
#endif #endif
bootloader_flash_update_id();
#if !CONFIG_SPIRAM_BOOT_INIT
// Read the application binary image header. This will also decrypt the header if the image is encrypted.
esp_image_header_t fhdr = {0};
#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM
fhdr.spi_mode = ESP_IMAGE_SPI_MODE_DIO;
fhdr.spi_speed = ESP_IMAGE_SPI_SPEED_40M;
fhdr.spi_size = ESP_IMAGE_FLASH_SIZE_4MB;
extern void esp_rom_spiflash_attach(uint32_t, bool);
esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false);
esp_rom_spiflash_unlock();
#else
// This assumes that DROM is the first segment in the application binary, i.e. that we can read
// the binary header through cache by accessing SOC_DROM_LOW address.
memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr));
#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM
// If psram is uninitialized, we need to improve some flash configuration.
bootloader_flash_clock_config(&fhdr);
bootloader_flash_gpio_config(&fhdr);
bootloader_flash_dummy_config(&fhdr);
bootloader_flash_cs_timing_config();
#endif //!CONFIG_SPIRAM_BOOT_INIT
spi_flash_init(); spi_flash_init();
/* init default OS-aware flash access critical section */ /* init default OS-aware flash access critical section */
spi_flash_guard_set(&g_flash_guard_default_ops); spi_flash_guard_set(&g_flash_guard_default_ops);
@ -424,20 +455,6 @@ void start_cpu0_default(void)
esp_coex_adapter_register(&g_coex_adapter_funcs); esp_coex_adapter_register(&g_coex_adapter_funcs);
#endif #endif
bootloader_flash_update_id();
#if !CONFIG_SPIRAM_BOOT_INIT
// Read the application binary image header. This will also decrypt the header if the image is encrypted.
esp_image_header_t fhdr = {0};
// This assumes that DROM is the first segment in the application binary, i.e. that we can read
// the binary header through cache by accessing SOC_DROM_LOW address.
memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr));
// If psram is uninitialized, we need to improve some flash configuration.
bootloader_flash_clock_config(&fhdr);
bootloader_flash_gpio_config(&fhdr);
bootloader_flash_dummy_config(&fhdr);
bootloader_flash_cs_timing_config();
#endif
portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_STACK, NULL,
ESP_TASK_MAIN_PRIO, NULL, 0); ESP_TASK_MAIN_PRIO, NULL, 0);

View file

@ -440,6 +440,13 @@ static uint32_t coex_status_get_wrapper(void)
#endif #endif
} }
static void coex_condition_set_wrapper(uint32_t type, bool dissatisfy)
{
#if CONFIG_SW_COEXIST_ENABLE
coex_condition_set(type, dissatisfy);
#endif
}
static int coex_wifi_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration) static int coex_wifi_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
{ {
#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE #if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE
@ -591,6 +598,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
._modem_sleep_register = esp_modem_sleep_register, ._modem_sleep_register = esp_modem_sleep_register,
._modem_sleep_deregister = esp_modem_sleep_deregister, ._modem_sleep_deregister = esp_modem_sleep_deregister,
._coex_status_get = coex_status_get_wrapper, ._coex_status_get = coex_status_get_wrapper,
._coex_condition_set = coex_condition_set_wrapper,
._coex_wifi_request = coex_wifi_request_wrapper, ._coex_wifi_request = coex_wifi_request_wrapper,
._coex_wifi_release = coex_wifi_release_wrapper, ._coex_wifi_release = coex_wifi_release_wrapper,
._magic = ESP_WIFI_OS_ADAPTER_MAGIC, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC,

View file

@ -49,6 +49,7 @@ MEMORY
/* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */ /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
iram0_0_seg (RX) : org = 0x40080000, len = 0x20000 iram0_0_seg (RX) : org = 0x40080000, len = 0x20000
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Even though the segment name is iram, it is actually mapped to flash /* Even though the segment name is iram, it is actually mapped to flash
*/ */
iram0_2_seg (RX) : org = 0x400D0020, len = 0x330000-0x20 iram0_2_seg (RX) : org = 0x400D0020, len = 0x330000-0x20
@ -60,6 +61,7 @@ MEMORY
header. Setting this offset makes it simple to meet the flash cache MMU's header. Setting this offset makes it simple to meet the flash cache MMU's
constraint that (paddr % 64KB == vaddr % 64KB).) constraint that (paddr % 64KB == vaddr % 64KB).)
*/ */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Shared data RAM, excluding memory reserved for ROM bss/data/stack. /* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
@ -74,10 +76,12 @@ MEMORY
dram0_0_seg (RW) : org = 0x3FFB0000 + CONFIG_BT_RESERVE_DRAM, dram0_0_seg (RW) : org = 0x3FFB0000 + CONFIG_BT_RESERVE_DRAM,
len = DRAM0_0_SEG_LEN - CONFIG_BT_RESERVE_DRAM len = DRAM0_0_SEG_LEN - CONFIG_BT_RESERVE_DRAM
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped constant data */ /* Flash mapped constant data */
drom0_0_seg (R) : org = 0x3F400020, len = 0x400000-0x20 drom0_0_seg (R) : org = 0x3F400020, len = 0x400000-0x20
/* (See iram0_2_seg for meaning of 0x20 offset in the above.) */ /* (See iram0_2_seg for meaning of 0x20 offset in the above.) */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* RTC fast memory (executable). Persists over deep sleep. /* RTC fast memory (executable). Persists over deep sleep.
*/ */
@ -118,3 +122,15 @@ REGION_ALIAS("rtc_data_location", rtc_slow_seg );
#else #else
REGION_ALIAS("rtc_data_location", rtc_data_seg ); REGION_ALIAS("rtc_data_location", rtc_data_seg );
#endif #endif
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_code_seg", iram0_2_seg);
#else
REGION_ALIAS("default_code_seg", iram0_0_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_rodata_seg", drom0_0_seg);
#else
REGION_ALIAS("default_rodata_seg", dram0_0_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS

View file

@ -161,12 +161,8 @@ SECTIONS
mapping[iram0_text] mapping[iram0_text]
_iram_text_end = ABSOLUTE(.); _iram_text_end = ABSOLUTE(.);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg } > iram0_0_seg
ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
"IRAM0 segment data does not fit.")
.dram0.data : .dram0.data :
{ {
_data_start = ABSOLUTE(.); _data_start = ABSOLUTE(.);
@ -312,7 +308,7 @@ SECTIONS
*(.tbss.*) *(.tbss.*)
_thread_local_end = ABSOLUTE(.); _thread_local_end = ABSOLUTE(.);
. = ALIGN(4); . = ALIGN(4);
} >drom0_0_seg } >default_rodata_seg
.flash.text : .flash.text :
{ {
@ -334,5 +330,25 @@ SECTIONS
the flash.text segment. the flash.text segment.
*/ */
_flash_cache_start = ABSOLUTE(0); _flash_cache_start = ABSOLUTE(0);
} >iram0_2_seg } >default_code_seg
/* Marks the end of IRAM code segment */
.iram0.text_end (NOLOAD) :
{
. = ALIGN (4);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg
/* Marks the end of data, bss and possibly rodata */
.dram0.heap_start (NOLOAD) :
{
. = ALIGN (8);
_heap_start = ABSOLUTE(.);
} > dram0_0_seg
} }
ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
"IRAM0 segment data does not fit.")
ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
"DRAM segment data does not fit.")

View file

@ -50,8 +50,12 @@ entries:
[scheme:default] [scheme:default]
entries: entries:
if APP_BUILD_USE_FLASH_SECTIONS = y:
text -> flash_text text -> flash_text
rodata -> flash_rodata rodata -> flash_rodata
else:
text -> iram0_text
rodata -> dram0_data
data -> dram0_data data -> dram0_data
bss -> dram0_bss bss -> dram0_bss
common -> dram0_bss common -> dram0_bss

View file

@ -450,7 +450,7 @@ static void esp_panic_dig_reset(void)
; ;
} }
} }
#endif #endif // CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
static void putEntry(uint32_t pc, uint32_t sp) static void putEntry(uint32_t pc, uint32_t sp)
{ {

View file

@ -247,11 +247,6 @@ typedef struct {
uint32_t sw_reset_timeout_ms; /*!< Software reset timeout value (Unit: ms) */ uint32_t sw_reset_timeout_ms; /*!< Software reset timeout value (Unit: ms) */
uint32_t rx_task_stack_size; /*!< Stack size of the receive task */ uint32_t rx_task_stack_size; /*!< Stack size of the receive task */
uint32_t rx_task_prio; /*!< Priority of the receive task */ uint32_t rx_task_prio; /*!< Priority of the receive task */
uint32_t queue_len; /*!< Length of the transaction queue */
#if CONFIG_ETH_USE_SPI_ETHERNET
spi_device_handle_t spi_hdl; /*!< Handle of spi device */
#endif
} eth_mac_config_t; } eth_mac_config_t;
/** /**
@ -263,7 +258,6 @@ typedef struct {
.sw_reset_timeout_ms = 100, \ .sw_reset_timeout_ms = 100, \
.rx_task_stack_size = 4096, \ .rx_task_stack_size = 4096, \
.rx_task_prio = 15, \ .rx_task_prio = 15, \
.queue_len = 100, \
} }
#if CONFIG_ETH_USE_ESP32_EMAC #if CONFIG_ETH_USE_ESP32_EMAC
@ -280,16 +274,34 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config);
#endif #endif
#if CONFIG_ETH_SPI_ETHERNET_DM9051 #if CONFIG_ETH_SPI_ETHERNET_DM9051
/**
* @brief DM9051 specific configuration
*
*/
typedef struct {
spi_device_handle_t spi_hdl; /*!< Handle of SPI device driver */
} eth_dm9051_config_t;
/**
* @brief Default DM9051 specific configuration
*
*/
#define ETH_DM9051_DEFAULT_CONFIG(spi_device) \
{ \
.spi_hdl = spi_device, \
}
/** /**
* @brief Create DM9051 Ethernet MAC instance * @brief Create DM9051 Ethernet MAC instance
* *
* @param config: Ethernet MAC configuration * @param dm9051_config: DM9051 specific configuration
* @param mac_config: Ethernet MAC configuration
* *
* @return * @return
* - instance: create MAC instance successfully * - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred * - NULL: create MAC instance failed because some error occurred
*/ */
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config); esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -815,16 +815,16 @@ static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac)
return ESP_OK; return ESP_OK;
} }
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config) esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config)
{ {
esp_eth_mac_t *ret = NULL; esp_eth_mac_t *ret = NULL;
MAC_CHECK(config, "can't set mac config to null", err, NULL); MAC_CHECK(dm9051_config, "can't set dm9051 specific config to null", err, NULL);
MAC_CHECK(config->spi_hdl, "can't set spi handle to null", err, NULL); MAC_CHECK(mac_config, "can't set mac config to null", err, NULL);
emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t)); emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t));
MAC_CHECK(emac, "calloc emac failed", err, NULL); MAC_CHECK(emac, "calloc emac failed", err, NULL);
/* bind methods and attributes */ /* bind methods and attributes */
emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms;
emac->spi_hdl = config->spi_hdl; emac->spi_hdl = dm9051_config->spi_hdl;
emac->parent.set_mediator = emac_dm9051_set_mediator; emac->parent.set_mediator = emac_dm9051_set_mediator;
emac->parent.init = emac_dm9051_init; emac->parent.init = emac_dm9051_init;
emac->parent.deinit = emac_dm9051_deinit; emac->parent.deinit = emac_dm9051_deinit;
@ -843,8 +843,8 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config)
emac->spi_lock = xSemaphoreCreateMutex(); emac->spi_lock = xSemaphoreCreateMutex();
MAC_CHECK(emac->spi_lock, "create lock failed", err_lock, NULL); MAC_CHECK(emac->spi_lock, "create lock failed", err_lock, NULL);
/* create dm9051 task */ /* create dm9051 task */
BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", config->rx_task_stack_size, emac, BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", mac_config->rx_task_stack_size, emac,
config->rx_task_prio, &emac->rx_task_hdl); mac_config->rx_task_prio, &emac->rx_task_hdl);
MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL); MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL);
return &(emac->parent); return &(emac->parent);
err_tsk: err_tsk:

View file

@ -1,31 +1,47 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/event_groups.h"
#include "tcpip_adapter.h" #include "tcpip_adapter.h"
#include "esp_event.h"
#include "unity.h" #include "unity.h"
#include "test_utils.h" #include "test_utils.h"
#include "esp_event.h"
#include "esp_eth.h" #include "esp_eth.h"
#include "esp_log.h" #include "esp_log.h"
#include "sdkconfig.h"
static const char *TAG = "esp_eth_test"; static const char *TAG = "esp_eth_test";
#define ETH_START_BIT BIT(0)
#define ETH_STOP_BIT BIT(1)
#define ETH_CONNECT_BIT BIT(2)
#define ETH_GOT_IP_BIT BIT(3)
#define ETH_START_TIMEOUT_MS (10000)
#define ETH_CONNECT_TIMEOUT_MS (40000)
#define ETH_STOP_TIMEOUT_MS (10000)
#define ETH_GET_IP_TIMEOUT_MS (60000)
/** Event handler for Ethernet events */ /** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base, static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) int32_t event_id, void *event_data)
{ {
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
switch (event_id) { switch (event_id) {
case ETHERNET_EVENT_CONNECTED: case ETHERNET_EVENT_CONNECTED:
xEventGroupSetBits(eth_event_group, ETH_CONNECT_BIT);
ESP_LOGI(TAG, "Ethernet Link Up"); ESP_LOGI(TAG, "Ethernet Link Up");
break; break;
case ETHERNET_EVENT_DISCONNECTED: case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down"); ESP_LOGI(TAG, "Ethernet Link Down");
break; break;
case ETHERNET_EVENT_START: case ETHERNET_EVENT_START:
xEventGroupSetBits(eth_event_group, ETH_START_BIT);
ESP_LOGI(TAG, "Ethernet Started"); ESP_LOGI(TAG, "Ethernet Started");
break; break;
case ETHERNET_EVENT_STOP: case ETHERNET_EVENT_STOP:
xEventGroupSetBits(eth_event_group, ETH_STOP_BIT);
ESP_LOGI(TAG, "Ethernet Stopped"); ESP_LOGI(TAG, "Ethernet Stopped");
break; break;
default: default:
@ -37,6 +53,7 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base,
static void got_ip_event_handler(void *arg, esp_event_base_t event_base, static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) int32_t event_id, void *event_data)
{ {
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
const tcpip_adapter_ip_info_t *ip_info = &event->ip_info; const tcpip_adapter_ip_info_t *ip_info = &event->ip_info;
@ -46,27 +63,31 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask)); ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw)); ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~"); ESP_LOGI(TAG, "~~~~~~~~~~~");
xEventGroupSetBits(eth_event_group, ETH_GOT_IP_BIT);
} }
TEST_CASE("esp32 emac io test", "[ethernet][ignore]") TEST_CASE("esp32 ethernet io test", "[ethernet][test_env=UT_T2_Ethernet]")
{ {
TEST_ESP_OK(esp_event_loop_create_default()); TEST_ESP_OK(esp_event_loop_create_default());
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL; esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle)); TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(1000));
/* get MAC address */ /* get MAC address */
uint8_t mac_addr[6]; uint8_t mac_addr[6];
memset(mac_addr, 0, sizeof(mac_addr)); memset(mac_addr, 0, sizeof(mac_addr));
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr));
ESP_LOGI(TAG, "Ethernet MAC Address: %d:%d:%d:%d:%d:%d",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
TEST_ASSERT(mac_addr[0] != 0); TEST_ASSERT(mac_addr[0] != 0);
/* get PHY address */ /* get PHY address */
int phy_addr = -1; int phy_addr = -1;
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr));
ESP_LOGI(TAG, "Ethernet PHY Address: %d", phy_addr);
TEST_ASSERT(phy_addr >= 0 && phy_addr <= 31); TEST_ASSERT(phy_addr >= 0 && phy_addr <= 31);
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(phy->del(phy));
@ -74,21 +95,65 @@ TEST_CASE("esp32 emac io test", "[ethernet][ignore]")
TEST_ESP_OK(esp_event_loop_delete_default()); TEST_ESP_OK(esp_event_loop_delete_default());
} }
TEST_CASE("ethernet tcpip_adapter", "[ethernet][ignore]") TEST_CASE("esp32 ethernet event test", "[ethernet][test_env=UT_T2_Ethernet]")
{ {
test_case_uses_tcpip(); EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
TEST_ESP_OK(esp_event_loop_create_default()); TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers()); TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL; esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle)); TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
vTaskDelay(portMAX_DELAY); /* wait for connection start */
bits = xEventGroupWaitBits(eth_event_group, ETH_START_BIT, true, true, pdMS_TO_TICKS(ETH_START_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_START_BIT) == ETH_START_BIT);
/* wait for connection establish */
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
/* wait for connection stop */
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
// "check link timer callback" might owned the reference of phy object, make sure it has release it
vTaskDelay(pdMS_TO_TICKS(2000));
TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
TEST_ESP_OK(esp_event_loop_delete_default());
vEventGroupDelete(eth_event_group);
}
TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]")
{
EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
test_case_uses_tcpip();
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers());
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, eth_event_group));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
/* wait for IP lease */
bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT);
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler));
TEST_ESP_OK(tcpip_adapter_clear_default_eth_handlers());
TEST_ESP_OK(esp_event_loop_delete_default());
vEventGroupDelete(eth_event_group);
} }
#if CONFIG_ETH_USE_SPI_ETHERNET #if CONFIG_ETH_USE_SPI_ETHERNET
@ -119,8 +184,8 @@ TEST_CASE("dm9051 io test", "[ethernet][ignore]")
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL)); TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.spi_hdl = spi_handle; eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);

View file

@ -8,6 +8,7 @@ PROVIDE ( esp_rom_spiflash_erase_area = 0x400631ac );
PROVIDE ( esp_rom_spiflash_erase_block = 0x40062c4c ); PROVIDE ( esp_rom_spiflash_erase_block = 0x40062c4c );
PROVIDE ( esp_rom_spiflash_erase_chip = 0x40062c14 ); PROVIDE ( esp_rom_spiflash_erase_chip = 0x40062c14 );
PROVIDE ( esp_rom_spiflash_erase_sector = 0x40062ccc ); PROVIDE ( esp_rom_spiflash_erase_sector = 0x40062ccc );
PROVIDE ( esp_rom_spiflash_attach = 0x40062a6c );
PROVIDE ( esp_rom_spiflash_lock = 0x400628f0 ); PROVIDE ( esp_rom_spiflash_lock = 0x400628f0 );
PROVIDE ( esp_rom_spiflash_read = 0x40062ed8 ); PROVIDE ( esp_rom_spiflash_read = 0x40062ed8 );
PROVIDE ( esp_rom_spiflash_config_readmode = 0x40062b64 ); /* SPIMasterReadModeCnfig */ PROVIDE ( esp_rom_spiflash_config_readmode = 0x40062b64 ); /* SPIMasterReadModeCnfig */

View file

@ -1,5 +1,5 @@
menu Wi-Fi menu "Wi-Fi"
config ESP32_WIFI_SW_COEXIST_ENABLE config ESP32_WIFI_SW_COEXIST_ENABLE
bool "Software controls WiFi/Bluetooth coexistence" bool "Software controls WiFi/Bluetooth coexistence"
@ -240,7 +240,7 @@ menu Wi-Fi
choice ESP32_WIFI_DEBUG_LOG_LEVEL choice ESP32_WIFI_DEBUG_LOG_LEVEL
depends on ESP32_WIFI_DEBUG_LOG_ENABLE depends on ESP32_WIFI_DEBUG_LOG_ENABLE
prompt "WiFi debug log level" prompt "WiFi debug log level"
default ESP32_WIFI_LOG_DEBUG default ESP32_WIFI_DEBUG_LOG_DEBUG
help help
The WiFi log is divided into the following levels: ERROR,WARNING,INFO,DEBUG,VERBOSE. The WiFi log is divided into the following levels: ERROR,WARNING,INFO,DEBUG,VERBOSE.
The ERROR,WARNING,INFO levels are enabled by default, and the DEBUG,VERBOSE levels can be enabled here. The ERROR,WARNING,INFO levels are enabled by default, and the DEBUG,VERBOSE levels can be enabled here.
@ -318,7 +318,7 @@ menu Wi-Fi
endmenu # Wi-Fi endmenu # Wi-Fi
menu PHY menu "PHY"
config ESP32_PHY_CALIBRATION_AND_DATA_STORAGE config ESP32_PHY_CALIBRATION_AND_DATA_STORAGE
# ToDo: remove once NVS and PHY partial calibration are supported # ToDo: remove once NVS and PHY partial calibration are supported

View file

@ -79,6 +79,12 @@ esp_err_t coex_preference_set(coex_prefer_t prefer);
*/ */
uint32_t coex_status_get(void); uint32_t coex_status_get(void);
/**
* @brief Set software coexist condition.
* @return : software coexist condition
*/
void coex_condition_set(uint32_t type, bool dissatisfy);
/** /**
* @brief WiFi requests coexistence. * @brief WiFi requests coexistence.
* *

View file

@ -21,7 +21,7 @@
extern "C" { extern "C" {
#endif #endif
#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000003 #define ESP_WIFI_OS_ADAPTER_VERSION 0x00000004
#define ESP_WIFI_OS_ADAPTER_MAGIC 0xDEADBEAF #define ESP_WIFI_OS_ADAPTER_MAGIC 0xDEADBEAF
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff #define OSI_FUNCS_TIME_BLOCKING 0xffffffff
@ -123,6 +123,7 @@ typedef struct {
int32_t (* _modem_sleep_register)(uint32_t module); int32_t (* _modem_sleep_register)(uint32_t module);
int32_t (* _modem_sleep_deregister)(uint32_t module); int32_t (* _modem_sleep_deregister)(uint32_t module);
uint32_t (* _coex_status_get)(void); uint32_t (* _coex_status_get)(void);
void (* _coex_condition_set)(uint32_t type, bool dissatisfy);
int32_t (* _coex_wifi_request)(uint32_t event, uint32_t latency, uint32_t duration); int32_t (* _coex_wifi_request)(uint32_t event, uint32_t latency, uint32_t duration);
int32_t (* _coex_wifi_release)(uint32_t event); int32_t (* _coex_wifi_release)(uint32_t event);
int32_t _magic; int32_t _magic;

@ -1 +1 @@
Subproject commit 3ea3a8f30c6cd5b29ccfb8b9b74d3e6741bdc1c2 Subproject commit 1266a879ba57e17c3d55a247b2a95bb9c4217505

View file

@ -85,7 +85,7 @@ static void sc_ack_send_task(void *pvParameters)
bzero(&server_addr, sizeof(struct sockaddr_in)); bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET; server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr((const char*)remote_ip); memcpy(&server_addr.sin_addr.s_addr, remote_ip, sizeof(remote_ip));
server_addr.sin_port = htons(remote_port); server_addr.sin_port = htons(remote_port);
esp_wifi_get_mac(WIFI_IF_STA, ack->ctx.mac); esp_wifi_get_mac(WIFI_IF_STA, ack->ctx.mac);

View file

@ -1,6 +1,6 @@
idf_component_register(REQUIRES bootloader) idf_component_register(REQUIRES bootloader)
if(NOT BOOTLOADER_BUILD) if(NOT BOOTLOADER_BUILD AND CONFIG_APP_BUILD_GENERATE_BINARIES)
string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_FLASH_OPTIONS}") string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_FLASH_OPTIONS}")
set(ESPTOOLPY_FLASH_PROJECT_OPTIONS set(ESPTOOLPY_FLASH_PROJECT_OPTIONS
"${ESPTOOLPY_FLASH_PROJECT_OPTIONS}" "${ESPTOOLPY_FLASH_PROJECT_OPTIONS}"

View file

@ -68,7 +68,11 @@ endif
APP_BIN_UNSIGNED ?= $(APP_BIN) APP_BIN_UNSIGNED ?= $(APP_BIN)
$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) | check_python_dependencies $(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) | check_python_dependencies
ifeq ("$(CONFIG_APP_BUILD_GENERATE_BINARIES)","y")
$(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $< $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
else
@echo "Skipping the BIN generation"
endif
ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
encrypted-flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies encrypted-flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies

@ -1 +1 @@
Subproject commit ecc72c54037eeae9b95e442246b8a92696518a3b Subproject commit 6d0d2c8df7fa598c5b42daf94e41fd2783f88730

View file

@ -78,7 +78,8 @@ set(PROJECT_BIN "${elf_name}.bin")
# #
# Add 'app.bin' target - generates with elf2image # Add 'app.bin' target - generates with elf2image
# #
add_custom_command(OUTPUT "${build_dir}/.bin_timestamp" if(CONFIG_APP_BUILD_GENERATE_BINARIES)
add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS} COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS}
-o "${build_dir}/${unsigned_project_binary}" "${elf}" -o "${build_dir}/${unsigned_project_binary}" "${elf}"
COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}" COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}"
@ -88,14 +89,17 @@ add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
WORKING_DIRECTORY ${build_dir} WORKING_DIRECTORY ${build_dir}
COMMENT "Generating binary image from built executable" COMMENT "Generating binary image from built executable"
) )
add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp") add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp")
endif()
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
"${build_dir}/${unsigned_project_binary}" "${build_dir}/${unsigned_project_binary}"
) )
add_custom_target(app ALL DEPENDS gen_project_binary) if(CONFIG_APP_BUILD_GENERATE_BINARIES)
add_custom_target(app ALL DEPENDS gen_project_binary)
endif()
if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS) if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)

View file

@ -20,7 +20,7 @@ menu "FreeRTOS"
choice FREERTOS_CORETIMER choice FREERTOS_CORETIMER
prompt "Xtensa timer to use as the FreeRTOS tick source" prompt "Xtensa timer to use as the FreeRTOS tick source"
default CONFIG_FREERTOS_CORETIMER_0 default FREERTOS_CORETIMER_0
help help
FreeRTOS needs a timer with an associated interrupt to use as FreeRTOS needs a timer with an associated interrupt to use as
the main tick source to increase counters, run timers and do the main tick source to increase counters, run timers and do

View file

@ -116,6 +116,19 @@ menu "mbedTLS"
default 3 if MBEDTLS_DEBUG_LEVEL_DEBUG default 3 if MBEDTLS_DEBUG_LEVEL_DEBUG
default 4 if MBEDTLS_DEBUG_LEVEL_VERBOSE default 4 if MBEDTLS_DEBUG_LEVEL_VERBOSE
config MBEDTLS_ECP_RESTARTABLE
bool "Enable mbedTLS ecp restartable"
default n
help
Enable "non-blocking" ECC operations that can return early and be resumed.
config MBEDTLS_CMAC_C
bool "Enable CMAC mode for block ciphers"
default n
help
Enable the CMAC (Cipher-based Message Authentication Code) mode for
block ciphers.
config MBEDTLS_HARDWARE_AES config MBEDTLS_HARDWARE_AES
bool "Enable hardware AES acceleration" bool "Enable hardware AES acceleration"
depends on IDF_TARGET_ESP32 depends on IDF_TARGET_ESP32

@ -1 +1 @@
Subproject commit 97959e77912524bd8db7cbb2e00fc9f6189f7a82 Subproject commit f5f2e5926cd294ae7cb579ff6a12ad9303caeb6e

View file

@ -253,6 +253,47 @@
#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES #define MBEDTLS_REMOVE_ARC4_CIPHERSUITES
#endif #endif
/**
* \def MBEDTLS_ECP_RESTARTABLE
*
* Enable "non-blocking" ECC operations that can return early and be resumed.
*
* This allows various functions to pause by returning
* #MBEDTLS_ERR_ECP_IN_PROGRESS (or, for functions in the SSL module,
* #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) and then be called later again in
* order to further progress and eventually complete their operation. This is
* controlled through mbedtls_ecp_set_max_ops() which limits the maximum
* number of ECC operations a function may perform before pausing; see
* mbedtls_ecp_set_max_ops() for more information.
*
* This is useful in non-threaded environments if you want to avoid blocking
* for too long on ECC (and, hence, X.509 or SSL/TLS) operations.
*
* Uncomment this macro to enable restartable ECC computations.
*
* \note This option only works with the default software implementation of
* elliptic curve functionality. It is incompatible with
* MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT and MBEDTLS_ECDSA_XXX_ALT.
*/
#ifdef CONFIG_MBEDTLS_ECP_RESTARTABLE
#define MBEDTLS_ECP_RESTARTABLE
#endif
/**
* \def MBEDTLS_CMAC_C
*
* Enable the CMAC (Cipher-based Message Authentication Code) mode for block
* ciphers.
*
* Module: library/cmac.c
*
* Requires: MBEDTLS_AES_C or MBEDTLS_DES_C
*
*/
#ifdef CONFIG_MBEDTLS_CMAC_C
#define MBEDTLS_CMAC_C
#endif
/** /**
* \def MBEDTLS_ECP_DP_SECP192R1_ENABLED * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED
* *

View file

@ -24,6 +24,7 @@ set(srcs
"port/http_parser.c") "port/http_parser.c")
idf_component_register(SRCS "${srcs}" idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS port/include nghttp2/lib/includes) INCLUDE_DIRS port/include nghttp2/lib/includes
PRIV_INCLUDE_DIRS private_include)
target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DHAVE_CONFIG_H") target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DHAVE_CONFIG_H")

View file

@ -4,6 +4,8 @@
COMPONENT_ADD_INCLUDEDIRS := port/include nghttp2/lib/includes COMPONENT_ADD_INCLUDEDIRS := port/include nghttp2/lib/includes
COMPONENT_PRIV_INCLUDEDIRS := private_include
COMPONENT_SRCDIRS := nghttp2/lib port COMPONENT_SRCDIRS := nghttp2/lib port
COMPONENT_SUBMODULES := nghttp2 COMPONENT_SUBMODULES := nghttp2

View file

@ -1,4 +1,4 @@
menu NVS menu "NVS"
config NVS_ENCRYPTION config NVS_ENCRYPTION
bool "Enable NVS encryption" bool "Enable NVS encryption"

View file

@ -1,6 +1,8 @@
Non-volatile storage library Non-volatile storage library
============================ ============================
:link_to_translation:`zh_CN:[中文]`
Introduction Introduction
------------ ------------

View file

@ -0,0 +1,303 @@
非易失性存储库
============================
:link_to_translation:`en:[English]`
简介
------------
非易失性存储 (NVS) 库主要用于在 flash 中存储键值格式的数据。本文档将详细介绍 NVS 常用的一些概念。
底层存储
^^^^^^^^^^^^^^^^^^
NVS 通过调用 ``spi_flash_{read|write|erase}`` API 对主 flash 的部分空间进行读、写、擦除操作,包括 ``data`` 类型和 ``nvs`` 子类型的所有分区。应用程序可调用 ``nvs_open`` API 选择使用带有 ``nvs`` 标签的分区,也可以通过调用 ``nvs_open_from_part`` API 选择使用指定名称的任意分区。
NVS 库后续版本可能会增加其他存储器后端,实现将数据保存至其他 flash 芯片SPI 或 I2C 接口、RTC 或 FRAM 中。
.. note:: 如果 NVS 分区被截断(例如,更改分区表布局时),则应擦除分区内容。可以使用 ESP-IDF 构建系统中的 ``idf.py erase_flash`` 命令擦除 flash 上的所有内容。
.. note:: NVS 最适合存储一些较小的数据,而非字符串或二进制大对象 (BLOB) 等较大的数据。如需存储较大的 BLOB 或者字符串,请考虑使用基于磨损均衡库的 FAT 文件系统。
键值对
^^^^^^^^^^^^^^^
NVS 的操作对象为键值对,其中键是 ASCII 字符串,当前支持最大键长为 15 个字符,值可以为以下几种类型:
- 整数型:``uint8_t````int8_t````uint16_t````int16_t````uint32_t````int32_t````uint64_t````int64_t``
- 以 ``\0`` 结尾的字符串;
- 可变长度的二进制数据 (BLOB)
.. note::
字符串值当前上限为 4000 字节其中包括空终止符。BLOB 值上限为 508,000 字节或分区大小减去 4000 字节的 97.6%,以较低值为准。
后续可能会增加对 ``float````double`` 等其他类型数据的支持。
键必须唯一。为现有的键写入新的值可能产生如下结果:
- 如果新旧值数据类型相同,则更新值;
- 如果新旧值数据类型不同,则返回错误。
读取值时也会执行数据类型检查。如果读取操作的数据类型与该值的数据类型不匹配,则返回错误。
命名空间
^^^^^^^^^^
为了减少不同组件之间键名的潜在冲突NVS 将每个键值对分配给一个命名空间。命名空间的命名规则遵循键名的命名规则,即最多可占 15 个字符。命名空间的名称在调用 ``nvs_open````nvs_open_from_part`` 中指定,调用后将返回一个不透明句柄,用于后续调用 ``nvs_read_*````nvs_write_*````nvs_commit`` 函数。这样,一个句柄关联一个命名空间,键名便不会与其他命名空间中相同键名冲突。请注意,不同 NVS 分区中具有相同名称的命名空间将被视为不同的命名空间。
安全性、篡改性及鲁棒性
^^^^^^^^^^^^^^^^^^^^^^^^^^
NVS 与 ESP32 flash 加密系统不直接兼容。但如果 NVS 加密与 ESP32 flash 加密一起使用时,数据仍可以加密形式存储。更多详情请参阅 :ref:`nvs_encryption`
如果未启用 NVS 加密,任何对 flash 芯片有物理访问权限的人都可以修改、擦除或添加键值对。NVS 加密启用后,如果不知道相应的 NVS 加密密钥,则无法修改或添加键值对并将其识别为有效键值。但是,针对擦除操作没有相应的防篡改功能。
当 flash 处于不一致状态时NVS 库会尝试恢复。在任何时间点关闭设备电源,然后重新打开电源,不会导致数据丢失;但如果关闭设备电源时正在写入新的键值对,这一键值对可能会丢失。该库还应当能对 flash 中的任意数据进行正确初始化。
内部实现
---------
键值对日志
^^^^^^^^^^^^^^^^^^^^^^
NVS 按顺序存储键值对,新的键值对添加在最后。因此,如需更新某一键值对,实际是在日志最后增加一对新的键值对,同时将旧的键值对标记为已擦除。
页面和条目
^^^^^^^^^^^^^^^^^
NVS 库在其操作中主要使用两个实体:页面和条目。页面是一个逻辑结构,用于存储部分的整体日志。逻辑页面对应 flash 的一个物理扇区,正在使用中的页面具有与之相关联的序列号。序列号赋予了页面顺序,较高的序列号对应较晚创建的页面。页面有以下几种状态:
空或未初始化
页面对应的 flash 扇区为空白状态(所有字节均为 ``0xff``)。此时,页面未存储任何数据且没有关联的序列号。
活跃状态
此时 flash 已完成初始化,页头部写入 flash页面已具备有效序列号。页面中存在一些空条目可写入数据。任意时刻至多有一个页面处于活跃状态。
写满状态
Flash 已写满键值对,状态不再改变。用户无法向写满状态下的页面写入新键值对,但仍可将一些键值对标记为已擦除。
擦除状态
未擦除的键值对将移至其他页面,以便擦除当前页面。这一状态仅为暂时性状态,即 API 调用返回时,页面应脱离这一状态。如果设备突然断电,下次开机时,设备将继续把未擦除的键值对移至其他页面,并继续擦除当前页面。
损坏状态
页头部包含无效数据,无法进一步解析该页面中的数据,因此之前写入该页面的所有条目均无法访问。相应的 flash 扇区并不会被立即擦除,而是与其他处于未初始化状态的扇区一起等待后续使用。这一状态可能对调试有用。
Flash 扇区映射至逻辑页面并没有特定的顺序NVS 库会检查存储在 flash 扇区的页面序列号,并根据序列号组织页面。
::
+--------+ +--------+ +--------+ +--------+
| Page 1 | | Page 2 | | Page 3 | | Page 4 |
| Full +---> | Full +---> | Active | | Empty | <- 状态
| #11 | | #12 | | #14 | | | <- 序列号
+---+----+ +----+---+ +----+---+ +---+----+
| | | |
| | | |
| | | |
+---v------+ +-----v----+ +------v---+ +------v---+
| Sector 3 | | Sector 0 | | Sector 2 | | Sector 1 | <- 物理扇区
+----------+ +----------+ +----------+ +----------+
页面结构
^^^^^^^^^^^^^^^^^^^
当前,我们假设 flash 扇区大小为 4096 字节,并且 ESP32 flash 加密硬件在 32 字节块上运行。未来有可能引入一些编译时可配置项(可通过 menuconfig 进行配置),以适配具有不同扇区大小的 flash 芯片。但目前尚不清楚 SPI flash 驱动和 SPI flash cache 之类的系统组件是否支持其他扇区大小。
页面由头部、条目状态位图和条目三部分组成。为了实现与 ESP32 flash 加密功能兼容,条目大小设置为 32 字节。如果键值为整数型,条目则保存一个键值对;如果键值为字符串或 BLOB 类型,则条目仅保存一个键值对的部分内容(更多信息详见条目结构描述)。
页面结构如下图所示,括号内数字表示该部分的大小(以字节为单位)::
+-----------+--------------+-------------+-------------------------+
| State (4) | Seq. no. (4) | version (1) | Unused (19) | CRC32 (4) | 页头部 (32)
+-----------+--------------+-------------+-------------------------+
| Entry state bitmap (32) |
+------------------------------------------------------------------+
| Entry 0 (32) |
+------------------------------------------------------------------+
| Entry 1 (32) |
+------------------------------------------------------------------+
/ /
/ /
+------------------------------------------------------------------+
| Entry 125 (32) |
+------------------------------------------------------------------+
头部和条目状态位图写入 flash 时不加密。如果启用了 ESP32 flash 加密功能,则条目写入 flash 时将会加密。
通过将 0 写入某些位可以定义页面状态值,表示状态改变。因此,如果需要变更页面状态,并不一定要擦除页面,除非要将其变更为擦除状态。
头部中的 ``version`` 字段反映了所用的 NVS 格式版本。为实现向后兼容,版本升级从 0xff 开始依次递减例如version-1 为 0xffversion-2 为 0xfe 等)。
头部中 CRC32 值是由不包含状态值的条目计算所得4 到 28 字节)。当前未使用的条目用 ``0xff`` 字节填充。
条目结构和条目状态位图详细信息见下文描述。
条目和条目状态位图
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
每个条目可处于以下三种状态之一,每个状态在条目状态位图中用两位表示。位图中的最后四位 (256 - 2 * 126) 未使用。
空 (2'b11)
条目还未写入任何内容,处于未初始化状态(全部字节为 ``0xff``)。
写入2'b10
一个键值对(或跨多个条目的键值对的部分内容)已写入条目中。
擦除2'b00
条目中的键值对已丢弃,条目内容不再解析。
.. _structure_of_entry:
条目结构
^^^^^^^^^^^^^^^^^^
如果键值类型为基础类型,即 1 - 8 个字节长度的整数型,条目将保存一个键值对;如果键值类型为字符串或 BLOB 类型条目将保存整个键值对的部分内容。另外如果键值为字符串类型且跨多个条目则键值所跨的所有条目均保存在同一页面。BLOB 则可以切分为多个块实现跨多个页面。BLOB 索引是一个附加的固定长度元数据条目,用于追踪 BLOB 块。目前条目仍支持早期 BLOB 格式(可读取可修改),但这些 BLOB 一经修改,即以新格式储存至条目。
::
+--------+----------+----------+----------------+-----------+---------------+----------+
| NS (1) | Type (1) | Span (1) | ChunkIndex (1) | CRC32 (4) | Key (16) | Data (8) |
+--------+----------+----------+----------------+-----------+---------------+----------+
Primitive +--------------------------------+
+--------> | Data (8) |
| Types +--------------------------------+
+-> Fixed length --
| | +---------+--------------+---------------+-------+
| +--------> | Size(4) | ChunkCount(1)| ChunkStart(1) | Rsv(2)|
Data format ---+ BLOB Index +---------+--------------+---------------+-------+
|
| +----------+---------+-----------+
+-> Variable length --> | Size (2) | Rsv (2) | CRC32 (4) |
(Strings, BLOB Data) +----------+---------+-----------+
条目结构中各个字段含义如下:
命名空间 (NS, NameSpace)
该条目的命名空间索引,详细信息见命名空间实现章节。
类型 (Type)
一个字节表示的值的数据类型,可能的类型见 ``nvs_types.h````ItemType`` 枚举。
跨度 (Span)
该键值对所用的条目数量。如果键值为整数型,条目数量即为 1。如果键值为字符串或 BLOB则条目数量取决于值的长度。
块索引 (ChunkIndex)
用于存储 BLOB 类型数据块的索引。如果键值为其他数据类型,则此处索引应写入 ``0xff``
CRC32
对条目下所有字节进行校验所得的校验和CRC32 字段不计算在内)。
键 (Key)
即以零结尾的 ASCII 字符串,字符串最长为 15 字节,不包含最后一个字节的 NULL (``\0``) 终止符。
数据 (Data)
如果键值类型为整数型,则数据字段仅包含键值。如果键值小于八个字节,使用 ``0xff`` 填充未使用的部分(右侧)。
如果键值类型为 BLOB 索引条目,则该字段的八个字节将保存以下数据块信息:
- 块大小
整个 BLOB 数据的大小(以字节为单位)。该字段仅用于 BLOB 索引类型条目。
- ChunkCount
存储过程中 BLOB 分成的数据块数量。该字段仅用于 BLOB 索引类型条目。
- ChunkStart
BLOB 第一个数据块的块索引,后续数据块索引依次递增,步长为 1。该字段仅用于 BLOB 索引类型条目。
如果键值类型为字符串或 BLOB 数据块,数据字段的这八个字节将保存该键值的一些附加信息,如下所示:
- 数据大小
实际数据的大小(以字节为单位)。如果键值类型为字符串,此字段也应将零终止符包含在内。此字段仅用于字符串和 BLOB 类型条目。
- CRC32
数据所有字节的校验和,该字段仅用于字符串和 BLOB 类型条目。
可变长度值(字符串和 BLOB写入后续条目每个条目 32 字节。第一个条目的 span 字段将指明使用了多少条目。
命名空间
^^^^^^^^^^
如上所述,每个键值对属于一个命名空间。命名空间标识符(字符串)也作为键值对的键,存储在索引为 0 的命名空间中。与这些键对应的值就是这些命名空间的索引。
::
+-------------------------------------------+
| NS=0 Type=uint8_t Key="wifi" Value=1 | Entry describing namespace "wifi"
+-------------------------------------------+
| NS=1 Type=uint32_t Key="channel" Value=6 | Key "channel" in namespace "wifi"
+-------------------------------------------+
| NS=0 Type=uint8_t Key="pwm" Value=2 | Entry describing namespace "pwm"
+-------------------------------------------+
| NS=2 Type=uint16_t Key="channel" Value=20 | Key "channel" in namespace "pwm"
+-------------------------------------------+
条目哈希列表
^^^^^^^^^^^^^^
为了减少对 flash 执行的读操作次数Page 类对象均设有一个列表,包含一对数据:条目索引和条目哈希值。该列表可大大提高检索速度,而无需迭代所有条目并逐个从 flash 中读取。``Page::findItem`` 首先从哈希列表中检索条目哈希值,如果条目存在,则在页面内给出条目索引。由于哈希冲突,在哈希列表中检索条目哈希值可能会得到不同的条目,对 flash 中条目再次迭代可解决这一冲突。
哈希列表中每个节点均包含一个 24 位哈希值和 8 位条目索引。哈希值根据条目命名空间、键名和块索引由 CRC32 计算所得,计算结果保留 24 位。为减少将 32 位条目存储在链表中的开销,链表采用了数组的双向链表。每个数组占用 128 个字节,包含 29 个条目、两个链表指针和一个 32 位计数字段。因此,每页额外需要的 RAM 最少为 128 字节,最多为 640 字节。
.. _nvs_encryption:
NVS 加密
--------------
NVS 分区内存储的数据可使用 AES-XTS 进行加密,类似于 IEEE P1619 磁盘加密标准中提到的加密方式。为了实现加密每个条目被均视为一个扇区并将条目相对地址相对于分区开头传递给加密算法用作扇区号。NVS 加密所需的密钥存储于其他分区,并进行了 :doc:`flash 加密 <../../security/flash-encryption>`。因此,在使用 NVS 加密前应先启用 :doc:`flash 加密 <../../security/flash-encryption>`
.. _nvs_key_partition:
NVS 密钥分区
^^^^^^^^^^^^^^^^^
应用程序如果想使用 NVS 加密,则需要编译进一个类型为 ``data``,子类型为 ``key`` 的密钥分区。该分区应标记为已加密,且最小为 4096 字节,具体结构见下表。如需了解更多详细信息,请参考 :doc:`分区表 <../../api-guides/partition-tables>`
::
+-----------+--------------+-------------+----+
| XTS encryption key(32) |
+---------------------------------------------+
| XTS tweak key (32) |
+---------------------------------------------+
| CRC32(4) |
+---------------------------------------------+
使用 NVS 分区生成程序生成上述分区表,并烧录至设备。由于分区已标记为已加密,而且启用了 :doc:`flash 加密 <../../security/flash-encryption>`,引导程序在首次启动时将使用 flash 加密对密钥分区进行加密。您也可以在设备启动后调用 ``nvs_flash.h`` 提供的 ``nvs_flash_generate_keys`` API 生成加密密钥,然后再将密钥以加密形式写入密钥分区。
应用程序可以使用不同的密钥对不同的 NVS 分区进行加密,这样就会需要多个加密密钥分区。应用程序应为加解密操作提供正确的密钥或密钥分区。
加密读取/写入
^^^^^^^^^^^^^^^^^^^^
``nvs_read_*````nvs_write_*`` 等 NVS API 函数同样可以对 NVS 加密分区执行读写操作。但用于初始化 NVS 非加密分区和加密分区的 API 则有所不同:初始化 NVS 非加密分区可以使用 ``nvs_flash_init````nvs_flash_init_partition``,但初始化 NVS 加密分区则需调用 ``nvs_flash_secure_init````nvs_flash_secure_init_partition``。上述 API 函数所需的 ``nvs_sec_cfg_t`` 结构可使用 ``nvs_flash_generate_keys`` 或者 ``nvs_flash_read_security_cfg`` 进行填充。
应用程序如需在加密状态下执行 NVS 读写操作,应遵循以下步骤:
1. 使用 ``esp_partition_find*`` API 查找密钥分区和 NVS 数据分区;
2. 使用 ``nvs_flash_read_security_cfg````nvs_flash_generate_keys`` API 填充 ``nvs_sec_cfg_t`` 结构;
3. 使用 ``nvs_flash_secure_init````nvs_flash_secure_init_partition`` API 初始化 NVS flash 分区;
4. 使用 ``nvs_open````nvs_open_from_part`` API 打开命名空间;
5. 使用 ``nvs_read_*````nvs_write_*`` API 执行 NVS 读取/写入操作;
6. 使用 ``nvs_flash_deinit`` API 释放已初始化的 NVS 分区。
NVS 迭代器
^^^^^^^^^^^^^
迭代器允许根据指定的分区名称、命名空间和数据类型轮询 NVS 中存储的键值对。
您可以使用以下函数,执行相关操作:
- ``nvs_entry_find``:返回一个不透明句柄,用于后续调用 ``nvs_entry_next````nvs_entry_info`` 函数;
- ``nvs_entry_next``:返回指向下一个键值对的迭代器;
- ``nvs_entry_info``:返回每个键值对的信息。
如果未找到符合标准的键值对,``nvs_entry_find````nvs_entry_next`` 将返回 NULL此时不必释放迭代器。若不再需要迭代器可使用 ``nvs_release_iterator`` 释放迭代器。

View file

@ -33,7 +33,7 @@ menu "OpenSSL"
choice OPENSSL_ASSERT choice OPENSSL_ASSERT
prompt "Select OpenSSL assert function" prompt "Select OpenSSL assert function"
default CONFIG_OPENSSL_ASSERT_EXIT default OPENSSL_ASSERT_EXIT
help help
OpenSSL function needs "assert" function to check if input parameters are valid. OpenSSL function needs "assert" function to check if input parameters are valid.

View file

@ -22,17 +22,17 @@ menu "Partition Table"
config PARTITION_TABLE_CUSTOM_FILENAME config PARTITION_TABLE_CUSTOM_FILENAME
string "Custom partition CSV file" if PARTITION_TABLE_CUSTOM string "Custom partition CSV file" if PARTITION_TABLE_CUSTOM
default partitions.csv default "partitions.csv"
help help
Name of the custom partition CSV filename. This path is evaluated Name of the custom partition CSV filename. This path is evaluated
relative to the project root directory. relative to the project root directory.
config PARTITION_TABLE_FILENAME config PARTITION_TABLE_FILENAME
string string
default partitions_singleapp.csv if PARTITION_TABLE_SINGLE_APP && !ESP32_ENABLE_COREDUMP_TO_FLASH default "partitions_singleapp.csv" if PARTITION_TABLE_SINGLE_APP && !ESP32_ENABLE_COREDUMP_TO_FLASH
default partitions_singleapp_coredump.csv if PARTITION_TABLE_SINGLE_APP && ESP32_ENABLE_COREDUMP_TO_FLASH default "partitions_singleapp_coredump.csv" if PARTITION_TABLE_SINGLE_APP && ESP32_ENABLE_COREDUMP_TO_FLASH
default partitions_two_ota.csv if PARTITION_TABLE_TWO_OTA && !ESP32_ENABLE_COREDUMP_TO_FLASH default "partitions_two_ota.csv" if PARTITION_TABLE_TWO_OTA && !ESP32_ENABLE_COREDUMP_TO_FLASH
default partitions_two_ota_coredump.csv if PARTITION_TABLE_TWO_OTA && ESP32_ENABLE_COREDUMP_TO_FLASH default "partitions_two_ota_coredump.csv" if PARTITION_TABLE_TWO_OTA && ESP32_ENABLE_COREDUMP_TO_FLASH
default PARTITION_TABLE_CUSTOM_FILENAME if PARTITION_TABLE_CUSTOM default PARTITION_TABLE_CUSTOM_FILENAME if PARTITION_TABLE_CUSTOM
config PARTITION_TABLE_OFFSET config PARTITION_TABLE_OFFSET

View file

@ -30,7 +30,7 @@ extern soc_reserved_region_t soc_reserved_memory_region_end;
These variables have the start and end of the data and static IRAM These variables have the start and end of the data and static IRAM
area used by the program. Defined in the linker script. area used by the program. Defined in the linker script.
*/ */
extern int _data_start, _static_data_end, _iram_start, _iram_end; extern int _data_start, _heap_start, _iram_start, _iram_end;
/* static DRAM & IRAM chunks */ /* static DRAM & IRAM chunks */
static const size_t EXTRA_RESERVED_REGIONS = 2; static const size_t EXTRA_RESERVED_REGIONS = 2;
@ -68,8 +68,8 @@ static void s_prepare_reserved_regions(soc_reserved_region_t *reserved, size_t c
(count - EXTRA_RESERVED_REGIONS) * sizeof(soc_reserved_region_t)); (count - EXTRA_RESERVED_REGIONS) * sizeof(soc_reserved_region_t));
/* Add the EXTRA_RESERVED_REGIONS at the beginning */ /* Add the EXTRA_RESERVED_REGIONS at the beginning */
reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss */ reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss and possibly rodata */
reserved[0].end = (intptr_t)&_static_data_end; reserved[0].end = (intptr_t)&_heap_start;
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
//ESP32 has a IRAM-only region 0x4008_0000 - 0x4009_FFFF, protect the used part //ESP32 has a IRAM-only region 0x4008_0000 - 0x4009_FFFF, protect the used part
reserved[1].start = (intptr_t)&_iram_start; /* IRAM used by code */ reserved[1].start = (intptr_t)&_iram_start; /* IRAM used by code */

View file

@ -1,6 +1,8 @@
SPI Flash API SPI Flash API
============= =============
:link_to_translation:`zh_CN:[中文]`
Overview Overview
-------- --------
The spi_flash component contains API functions related to reading, writing, The spi_flash component contains API functions related to reading, writing,

View file

@ -0,0 +1,188 @@
SPI Flash API
=================
:link_to_translation:`en:[English]`
概述
--------
SPI Flash 组件提供外部 flash 数据读取、写入、擦除和内存映射相关的 API 函数,同时也提供了更高层级的,面向分区的 API 函数(定义在 :doc:`分区表 </api-guides/partition-tables>` 中)。
与 ESP-IDF V4.0 之前的 API 不同,这一版 API 功能并不局限于主 SPI Flash 芯片(即运行程序的 SPI Flash 芯片)。使用不同的芯片指针,您可以通过 SPI0/1 或 HSPI/VSPI 总线访问外部 flash。
.. note::
ESP-IDF V4.0 之后的 flash API 不再是原子的。因此,如果 flash 操作地址有重叠,且写操作与读操作同时执行,读操作可能会返回一部分写入之前的数据,返回一部分写入之后的数据。
Kconfig 选项 :ref:`CONFIG_SPI_FLASH_USE_LEGACY_IMPL` 可将 ``spi_flash_*`` 函数切换至 ESP-IDF V4.0 之前的实现。但是,如果同时使用新旧 API代码量可能会增多。
即便未启用 :ref:`CONFIG_SPI_FLASH_USE_LEGACY_IMPL`,加密读取和加密写入操作也均使用旧实现。因此,仅有主 flash 芯片支持加密操作,其他不同片选(经 SPI1 访问的 flash 芯片)则不支持加密操作。
初始化 Flash 设备
---------------------------
在使用 ``esp_flash_*`` API 之前,您需要在 SPI 总线上初始化芯片。
1. 调用 :cpp:func:`spi_bus_initialize` 初始化 SPI 总线,此函数将初始化总线上设备间共享的资源,如 I/O、DMA 及中断等。
2. 调用 :cpp:func:`spi_bus_add_flash_device` 将 flash 设备连接到总线上。然后分配内存,填充 ``esp_flash_t`` 结构体,同时初始化 CS I/O。
3. 调用 :cpp:func:`esp_flash_init` 与芯片进行通信。后续操作会依据芯片类型不同而有差异。
.. note:: 目前,多个 flash 芯片可连接到同一总线。但尚不支持在同一个 SPI 总线上使用 ``esp_flash_*````spi_device_*`` 设备。
SPI Flash 访问 API
--------------------
如下所示为处理 flash 中数据的函数集:
- :cpp:func:`esp_flash_read`:将数据从 flash 读取到 RAM
- :cpp:func:`esp_flash_write`:将数据从 RAM 写入到 flash
- :cpp:func:`esp_flash_erase_region`:擦除 flash 中指定区域的数据;
- :cpp:func:`esp_flash_erase_chip`:擦除整个 flash
- :cpp:func:`esp_flash_get_chip_size`:返回 menuconfig 中设置的 flash 芯片容量(以字节为单位)。
一般来说,请尽量避免对主 SPI flash 芯片直接使用原始 SPI flash 函数,如需对主 SPI flash 芯片进行操作,请使用 :ref:`分区专用函数 <flash-partition-apis>`
SPI Flash 容量
--------------
SPI flash 容量存储于引导程序映像头部(烧录偏移量为 0x1000的一个字段。
默认情况下,引导程序写入 flash 时esptool.py 将引导程序写入 flash 时,会自动检测 SPI flash 容量,同时使用正确容量更新引导程序的头部。您也可以在工程配置中设置 :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE`,生成固定的 flash 容量。
如需在运行时覆盖已配置的 flash 容量,请配置 ``g_rom_flashchip`` 结构中的 ``chip_size````esp_flash_*`` 函数使用此容量(于软件和 ROM 中)进行边界检查。
SPI1 Flash 并发约束
-----------------------------------------
由于 SPI1 flash 也被用于执行固件(通过指令 cache 或数据 cache ),因此在执行读取、写入及擦除操作时,必须禁用这些 cache。这意味着在执行 flash 写操作时,两个 CPU 必须从 IRAM 运行代码,且只能从 DRAM 中读取数据。
如果您使用本文档中 API 函数,上述限制将自动生效且透明(无需您额外关注),但这些限制可能会影响系统中的其他任务的性能。
除 SPI0/1 以外的 SPI 总线上的其它 flash 芯片则不受这种限制。
请参阅 :ref:`应用程序内存分布 <memory-layout>`,查看 IRAM、DRAM 和 flash cache 的区别。
为避免意外读取 flash cache一个 CPU 在启动 flash 写入或擦除操作时,另一个 CPU 将阻塞,并且在 flash 操作完成前,两个 CPU 上的所有的非 IRAM 安全的中断都会被禁用。
.. _iram-safe-interrupt-handlers:
IRAM 安全中断处理程序
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如果您需要在 flash 操作期间运行中断处理程序(比如低延迟操作),请在 :doc:`注册中断处理程序 </api-reference/system/intr_alloc>` 时设置 ``ESP_INTR_FLAG_IRAM``
请确保中断处理程序访问的所有数据和函数(包括其调用的数据和函数)都存储在 IRAM 或 DRAM 中。
为函数添加 ``IRAM_ATTR`` 属性::
#include "esp_attr.h"
void IRAM_ATTR gpio_isr_handler(void* arg)
{
// ...
}
为常量添加 ``DRAM_ATTR````DRAM_STR`` 属性::
void IRAM_ATTR gpio_isr_handler(void* arg)
{
const static DRAM_ATTR uint8_t INDEX_DATA[] = { 45, 33, 12, 0 };
const static char *MSG = DRAM_STR("I am a string stored in RAM");
}
辨别哪些数据应标记为 ``DRAM_ATTR`` 可能会比较困难,除非明确标记为 ``DRAM_ATTR``,否则编译器依然可能将某些变量或表达式当做常量(即便没有 ``const`` 标记),并将其放入 flash。
如果函数或符号未被正确放入 IRAM/DRAM 中,当中断处理程序在 flash 操作期间从 flash cache 中读取数据,则会产生非法指令异常(这是因为代码未被正确放入 IRAM或读取垃圾数据这是因为常数未被正确放入 DRAM而导致崩溃。
.. _flash-partition-apis:
分区表 API
-------------------
ESP-IDF 工程使用分区表保存 SPI flash 各区信息,包括引导程序、各种应用程序二进制文件、数据及文件系统等。请参考 :doc:`分区表 </api-guides/partition-tables>`,查看详细信息。
该组件在 ``esp_partition.h`` 中声明了一些 API 函数,用以枚举在分区表中找到的分区,并对这些分区执行操作:
- :cpp:func:`esp_partition_find`:在分区表中查找特定类型的条目,返回一个不透明迭代器;
- :cpp:func:`esp_partition_get`:返回一个结构,描述给定迭代器的分区;
- :cpp:func:`esp_partition_next`:将迭代器移至下一个找到的分区;
- :cpp:func:`esp_partition_iterator_release`:释放 ``esp_partition_find`` 中返回的迭代器;
- :cpp:func:`esp_partition_find_first`:返回一个结构,描述 ``esp_partition_find`` 中找到的第一个分区;
- :cpp:func:`esp_partition_read`:cpp:func:`esp_partition_write`:cpp:func:`esp_partition_erase_range` 在分区边界内执行,等同于 :cpp:func:`spi_flash_read`:cpp:func:`spi_flash_write`:cpp:func:`spi_flash_erase_range`
.. note::
请在应用程序代码中使用上述 ``esp_partition_*`` API 函数,而非低层级的 ``spi_flash_*`` API 函数。分区表 API 函数根据存储在分区表中的数据,进行边界检查并计算在 flash 中的正确偏移量。
SPI Flash 加密
--------------------
您可以对 SPI flash 内容进行加密,并在硬件层对其进行透明解密。
请参阅 :doc:`Flash 加密 </security/flash-encryption>`,查看详细信息。
内存映射 API
------------------
ESP32 内存硬件可以将 flash 部分区域映射到指令地址空间和数据地址空间,此映射仅用于读操作。不能通过写入 flash 映射的存储区域来改变 flash 中内容。
Flash 以 64 KB 页为单位进行地址映射。内存映射硬件最多可将 4 MB flash 映射到数据地址空间,将 16 MB flash 映射到指令地址空间。请参考《ESP32 技术参考手册》查看内存映射硬件的详细信息。
请注意,有些 64 KB 页还用于将应用程序映射到内存中,因此实际可用的 64 KB 页会更少一些。
:doc:`Flash 加密 </security/flash-encryption>` 启用时,使用内存映射区域从 flash 读取数据是解密 flash 的唯一方法,解密需在硬件层进行。
内存映射 API 在 ``esp_spi_flash.h````esp_partition.h`` 中声明:
- :cpp:func:`spi_flash_mmap`:将 flash 物理地址区域映射到 CPU 指令空间或数据空间;
- :cpp:func:`spi_flash_munmap`:取消上述区域的映射;
- :cpp:func:`esp_partition_mmap`:将分区的一部分映射至 CPU 指令空间或数据空间;
:cpp:func:`spi_flash_mmap`:cpp:func:`esp_partition_mmap` 的区别如下:
- :cpp:func:`spi_flash_mmap`:需要给定一个 64 KB 对齐的物理地址;
- :cpp:func:`esp_partition_mmap`:给定分区内任意偏移量即可,此函数根据需要将返回的指针调整至指向映射内存。
内存映射在 64 KB 块中进行,如果分区已传递给 ``esp_partition_mmap``,则可读取分区外数据。
实现
--------------
``esp_flash_t`` 结构包含芯片数据和该 API 的三个重要部分:
1. 主机驱动,为访问芯片提供硬件支持;
2. 芯片驱动,为不同芯片提供兼容性服务;
3. OS 函数,在不同阶段(一级或二级 Boot 或者应用程序阶段)为部分 OS 函数提供支持(如一些锁、延迟)。
主机驱动
^^^^^^^^^^^^^^^
主机驱动依赖 ``soc/include/hal`` 文件夹下 ``spi_flash_host_drv.h`` 定义的 ``spi_flash_host_driver_t`` 接口。该接口提供了一些与芯片通信常用的函数。
在 SPI HAL 文件中,有些函数是基于现有的 ESP32 memory-spi 来实现的。但是,由于 ESP32 速度限制HAL 层无法提供某些读命令的高速实现(所以这些命令根本没有在 HAL 的文件中被实现)。``memspi_host_driver.h````.c`` 文件使用 HAL 提供的 ``common_command`` 函数实现上述读命令的高速版本,并将所有它实现的及 HAL 函数封装为 ``spi_flash_host_driver_t`` 供更上层调用。
您也可以实现自己的主机驱动,甚至只通过简单的 GPIO。只要实现了 ``spi_flash_host_driver_t`` 中所有函数不管底层硬件是什么esp_flash API 都可以访问 flash。
芯片驱动
^^^^^^^^^^^
芯片驱动在 ``spi_flash_chip_driver.h`` 中进行定义,并将主机驱动提供的基本函数进行封装以供 API 层使用。
有些操作需在执行前先发送命令,或在执行后读取状态,因此有些芯片需要不同的命令或值以及通信方式。
``generic chip`` 芯片代表了常见的 flash 芯片,其他芯片驱动可以在通用芯片的基础上进行开发。
芯片驱动依赖主机驱动。
OS 函数
^^^^^^^^^^^^
OS 函数层提供访问锁和延迟的方法。
该锁定用于解决 SPI Flash 芯片访问和其他函数之间的冲突。例如,经 SPI0/1 访问 flash 芯片时,应当禁用 cache平时用于取代码和 PSRAM 数据)。另一种情况是,一些没有 CS 线或者 CS 线受软件控制的设备(如通过 SPI 接口的 SD 卡控制)需要在一段时间内独占总线。
延时则用于某些长时操作,需要主机处于等待状态或执行轮询。
顶层 API 将芯片驱动和 OS 函数封装成一个完整的组件,并提供参数检查。

View file

@ -634,7 +634,7 @@ esp_err_t esp_flash_app_disable_protect(bool disable)
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL #ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
static esp_err_t spi_flash_translate_rc(esp_err_t err) static IRAM_ATTR esp_err_t spi_flash_translate_rc(esp_err_t err)
{ {
switch (err) { switch (err) {
case ESP_OK: case ESP_OK:
@ -657,19 +657,19 @@ static esp_err_t spi_flash_translate_rc(esp_err_t err)
return ESP_OK; return ESP_OK;
} }
esp_err_t spi_flash_erase_range(uint32_t start_addr, uint32_t size) esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size)
{ {
esp_err_t err = esp_flash_erase_region(NULL, start_addr, size); esp_err_t err = esp_flash_erase_region(NULL, start_addr, size);
return spi_flash_translate_rc(err); return spi_flash_translate_rc(err);
} }
esp_err_t spi_flash_write(size_t dst, const void *srcv, size_t size) esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
{ {
esp_err_t err = esp_flash_write(NULL, srcv, dst, size); esp_err_t err = esp_flash_write(NULL, srcv, dst, size);
return spi_flash_translate_rc(err); return spi_flash_translate_rc(err);
} }
esp_err_t spi_flash_read(size_t src, void *dstv, size_t size) esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size)
{ {
esp_err_t err = esp_flash_read(NULL, dstv, src, size); esp_err_t err = esp_flash_read(NULL, dstv, src, size);
return spi_flash_translate_rc(err); return spi_flash_translate_rc(err);

View file

@ -55,27 +55,38 @@ typedef struct esp_partition_iterator_opaque_ {
static esp_partition_iterator_opaque_t* iterator_create(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label); static esp_partition_iterator_opaque_t* iterator_create(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label);
static esp_err_t load_partitions(void); static esp_err_t load_partitions(void);
static esp_err_t ensure_partitions_loaded(void);
static const char* TAG = "partition";
static SLIST_HEAD(partition_list_head_, partition_list_item_) s_partition_list = static SLIST_HEAD(partition_list_head_, partition_list_item_) s_partition_list =
SLIST_HEAD_INITIALIZER(s_partition_list); SLIST_HEAD_INITIALIZER(s_partition_list);
static _lock_t s_partition_list_lock; static _lock_t s_partition_list_lock;
esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, static esp_err_t ensure_partitions_loaded(void)
esp_partition_subtype_t subtype, const char* label)
{ {
esp_err_t err = ESP_OK;
if (SLIST_EMPTY(&s_partition_list)) { if (SLIST_EMPTY(&s_partition_list)) {
// only lock if list is empty (and check again after acquiring lock) // only lock if list is empty (and check again after acquiring lock)
_lock_acquire(&s_partition_list_lock); _lock_acquire(&s_partition_list_lock);
esp_err_t err = ESP_OK;
if (SLIST_EMPTY(&s_partition_list)) { if (SLIST_EMPTY(&s_partition_list)) {
ESP_LOGD(TAG, "Loading the partition table");
err = load_partitions(); err = load_partitions();
if (err != ESP_OK) {
ESP_LOGE(TAG, "load_partitions returned 0x%x", err);
}
} }
_lock_release(&s_partition_list_lock); _lock_release(&s_partition_list_lock);
if (err != ESP_OK) {
return NULL;
} }
return err;
}
esp_partition_iterator_t esp_partition_find(esp_partition_type_t type,
esp_partition_subtype_t subtype, const char* label)
{
if (ensure_partitions_loaded() != ESP_OK) {
return NULL;
} }
// create an iterator pointing to the start of the list // create an iterator pointing to the start of the list
// (next item will be the first one) // (next item will be the first one)
@ -233,6 +244,11 @@ esp_err_t esp_partition_register_external(esp_flash_t* flash_chip, size_t offset
return ESP_ERR_INVALID_SIZE; return ESP_ERR_INVALID_SIZE;
} }
esp_err_t err = ensure_partitions_loaded();
if (err != ESP_OK) {
return err;
}
partition_list_item_t* item = (partition_list_item_t*) calloc(sizeof(partition_list_item_t), 1); partition_list_item_t* item = (partition_list_item_t*) calloc(sizeof(partition_list_item_t), 1);
if (item == NULL) { if (item == NULL) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;

View file

@ -1,6 +1,8 @@
Virtual filesystem component Virtual filesystem component
============================ ============================
:link_to_translation:`zh_CN:[中文]`
Overview Overview
-------- --------

View file

@ -0,0 +1,167 @@
虚拟文件系统组件
============================
:link_to_translation:`en:[English]`
概述
--------
虚拟文件系统 (VFS) 组件可为一些驱动提供一个统一接口。有了该接口,用户可像操作普通文件一样操作虚拟文件。这类驱动程序可以是 FAT、SPIFFS 等真实文件系统,也可以是有文件类接口的设备驱动程序。
VFS 组件支持 C 库函数(如 fopen 和 fprintf 等)与文件系统 (FS) 驱动程序协同工作。在高层级,每个 FS 驱动程序均与某些路径前缀相关联。当一个 C 库函数需要打开文件时VFS 组件将搜索与该文件所在文件路径相关联的 FS 驱动程序,并将调用传递给该驱动程序。针对该文件的读取、写入等其他操作的调用也将传递给这个驱动程序。
例如,您可以使用 ``/fat`` 前缀注册 FAT 文件系统驱动,之后即可调用 ``fopen("/fat/file.txt", "w")``。之后VFS 将调用 FAT 驱动的 ``open`` 函数,并将参数 ``/file.txt`` 和合适的打开模式传递给 ``open`` 函数;后续对返回的 ``FILE*`` 数据流调用 C 库函数也同样会传递给 FAT 驱动。
注册 FS 驱动程序
---------------------
如需注册 FS 驱动程序,首先要定义一个 :cpp:type:`esp_vfs_t` 结构体实例,并用指向 FS API 的函数指针填充它。
.. highlight:: c
::
esp_vfs_t myfs = {
.flags = ESP_VFS_FLAG_DEFAULT,
.write = &myfs_write,
.open = &myfs_open,
.fstat = &myfs_fstat,
.close = &myfs_close,
.read = &myfs_read,
};
ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL));
在上述代码中需要用到 ``read````write````read_p````write_p``,具体使用哪组函数由 FS 驱动程序 API 的声明方式决定。
示例 1声明 API 函数时不带额外的上下文指针参数,即 FS 驱动程序为单例模式,此时使用 ``write`` ::
ssize_t myfs_write(int fd, const void * data, size_t size);
// In definition of esp_vfs_t:
.flags = ESP_VFS_FLAG_DEFAULT,
.write = &myfs_write,
// ... other members initialized
// When registering FS, context pointer (third argument) is NULL:
ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL));
示例 2声明 API 函数时需要一个额外的上下文指针作为参数,即可支持多个 FS 驱动程序实例,此时使用 ``write_p`` ::
ssize_t myfs_write(myfs_t* fs, int fd, const void * data, size_t size);
// In definition of esp_vfs_t:
.flags = ESP_VFS_FLAG_CONTEXT_PTR,
.write_p = &myfs_write,
// ... other members initialized
// When registering FS, pass the FS context pointer into the third argument
// (hypothetical myfs_mount function is used for illustrative purposes)
myfs_t* myfs_inst1 = myfs_mount(partition1->offset, partition1->size);
ESP_ERROR_CHECK(esp_vfs_register("/data1", &myfs, myfs_inst1));
// Can register another instance:
myfs_t* myfs_inst2 = myfs_mount(partition2->offset, partition2->size);
ESP_ERROR_CHECK(esp_vfs_register("/data2", &myfs, myfs_inst2));
同步输入/输出多路复用
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如需通过 :cpp:func:`select` 使用同步输入/输出多路复用,首先需要把 :cpp:func:`start_select`:cpp:func:`end_select` 注册到 VFS如下所示
.. highlight:: c
::
// In definition of esp_vfs_t:
.start_select = &uart_start_select,
.end_select = &uart_end_select,
// ... other members initialized
调用 :cpp:func:`start_select` 设置环境,用以检测某一 VFS 文件描述符的读取/写入/错误条件。调用 :cpp:func:`end_select` 终止、析构或释放 :cpp:func:`start_select` 设置的资源。请在 :component_file:`vfs/vfs_uart.c` 中查看 UART 外设参考实现、:cpp:func:`esp_vfs_dev_uart_register`:cpp:func:`uart_start_select`:cpp:func:`uart_end_select` 函数。
请参考以下示例,查看如何使用 VFS 文件描述符调用 :cpp:func:`select`
- :example:`peripherals/uart_select`
- :example:`system/select`
如果 :cpp:func:`select` 用于套接字文件描述符,您可以启用 :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` 选项来减少代码量,提高性能。
路径
-----
已注册的 FS 驱动程序均有一个路径前缀与之关联,此路径前缀即为分区的挂载点。
如果挂载点中嵌套了其他挂载点,则在打开文件时使用具有最长匹配路径前缀的挂载点。例如,假设以下文件系统已在 VFS 中注册:
- 在 /data 下注册 FS 驱动程序 1
- 在 /data/static 下注册 FS 驱动程序 2
那么:
- 打开 ``/data/log.txt`` 会调用驱动程序 FS 1
- 打开 ``/data/static/index.html`` 需调用 FS 驱动程序 2
- 即便 FS 驱动程序 2 中没有 ``/index.html``,也不会在 FS 驱动程序 1 中查找 ``/static/index.html``
挂载点名称必须以路径分隔符 (``/``) 开头且分隔符后至少包含一个字符。但在以下情况中VFS 同样支持空的挂载点名称1. 应用程序需要提供一个”最后方案“下使用的文件系统2. 应用程序需要同时覆盖 VFS 功能。如果没有与路径匹配的前缀,就会使用到这种文件系统。
VFS 不会对路径中的点 (``.``) 进行特殊处理,也不会将 ``..`` 视为对父目录的引用。在上述示例中,使用 ``/data/static/../log.txt`` 路径不会调用 FS 驱动程序 1 打开 ``/log.txt``。特定的 FS 驱动程序(如 FATFS可能以不同的方式处理文件名中的点。
执行打开文件操作时FS 驱动程序仅得到文件的相对路径(挂载点前缀已经被去除):
1. 以 ``/data`` 为路径前缀注册 ``myfs`` 驱动;
2. 应用程序调用 ``fopen("/data/config.json", ...)``
3. VFS 调用 ``myfs_open("/config.json", ...)``
4. ``myfs`` 驱动打开 ``/config.json`` 文件。
VFS 对文件路径长度没有限制,但文件系统路径前缀受 ``ESP_VFS_PATH_MAX`` 限制,即路径前缀上限为 ``ESP_VFS_PATH_MAX``。各个文件系统驱动则可能会对自己的文件名长度设置一些限制。
文件描述符
----------------
文件描述符是一组很小的正整数,从 ``0````FD_SETSIZE - 1````FD_SETSIZE`` 在 newlib ``sys/types.h`` 中定义。最大文件描述符由 ``CONFIG_LWIP_MAX_SOCKETS`` 定义且为套接字保留。VFS 中包含一个名为 ``s_fd_table`` 的查找表,用于将全局文件描述符映射至 ``s_vfs`` 数组中注册的 VFS 驱动索引。
标准 IO 流 (stdin, stdout, stderr)
-------------------------------------------
如果 menuconfig 中 ``UART for console output`` 选项没有设置为 ``None``,则 ``stdin````stdout````stderr`` 将默认从 UART 读取或写入。UART0 或 UART1 可用作标准 IO。默认情况下UART0 使用 115200 波特率TX 管脚为 GPIO1RX 管脚为 GPIO3。您可以在 menuconfig 中更改上述参数。
``stdout````stderr`` 执行写入操作将会向 UART 发送 FIFO 发送字符,对 ``stdin`` 执行读取操作则会从 UART 接收 FIFO 中取出字符。
默认情况下VFS 使用简单的函数对 UART 进行读写操作。在所有数据放进 UART FIFO 之前,写操作将处于 busy-wait 状态,读操处于非阻塞状态,仅返回 FIFO 中已有数据。由于读操作为非阻塞,高层级 C 库函数调用(如 ``fscanf("%d\n", &var);``)可能获取不到所需结果。
如果应用程序使用 UART 驱动,则可以调用 ``esp_vfs_dev_uart_use_driver`` 函数来指导 VFS 使用驱动中断、读写阻塞功能等。您也可以调用 ``esp_vfs_dev_uart_use_nonblocking`` 来恢复非阻塞函数。
VFS 还为输入和输出提供换行符转换功能(可选)。多数应用程序在程序内部发送或接收以 LF (''\n'') 结尾的行,但不同的终端程序可能需要不同的换行符,比如 CR 或 CRLF。应用程序可以通过 menuconfig 或者调用 ``esp_vfs_dev_uart_set_rx_line_endings````esp_vfs_dev_uart_set_tx_line_endings`` 为输入输出配置换行符。
标准流和 FreeRTOS 任务
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``stdin````stdout````stderr````FILE`` 对象在所有 FreeRTOS 任务之间共享,指向这些对象的指针分别存储在每个任务的 ``struct _reent`` 中。
预处理器把如下代码:
.. highlight:: c
::
fprintf(stderr, "42\n");
解释为:
.. highlight:: c
::
fprintf(__getreent()->_stderr, "42\n");
其中 ``__getreent()`` 函数将为每个任务返回一个指向 ``struct _reent`` 的指针 (:component_file:`newlib/include/sys/reent.h#L370-L417`)。每个任务的 TCB 均拥有一个 ``struct _reent`` 结构体,任务初始化后,``struct _reent`` 结构体中的 ``_stdin````_stdout````_stderr`` 将会被赋予 ``_GLOBAL_REENT````_stdin````_stdout````_stderr`` 的值,``_GLOBAL_REENT`` 即为 FreeRTOS 启动之前所用结构体。
这样设计带来的结果是:
- 允许重定向给定任务的 ``stdin````stdout````stderr``,而不影响其他任务,例如通过 ``stdin = fopen("/dev/uart/1", "r")``
- 但使用 ``fclose`` 关闭默认 ``stdin````stdout````stderr`` 将同时关闭相应的 ``FILE`` 流对象,因此会影响其他任务;
- 如需更改新任务的默认 ``stdin````stdout````stderr`` 流,请在创建新任务之前修改 ``_GLOBAL_REENT->_stdin`` (``_stdout````_stderr``)。

View file

@ -24,7 +24,7 @@ ESP-IDF Tools Installer
The easiest way to install ESP-IDF's prerequisites is to download the ESP-IDF Tools installer from this URL: The easiest way to install ESP-IDF's prerequisites is to download the ESP-IDF Tools installer from this URL:
https://dl.espressif.com/dl/esp-idf-tools-setup-2.0.exe https://dl.espressif.com/dl/esp-idf-tools-setup-2.1.exe
The installer includes the cross-compilers, OpenOCD, cmake_ and Ninja_ build tool, and a configuration tool called mconf-idf_. The installer can also download and run installers for Python_ 3.7 and `Git For Windows`_ if they are not already installed on the computer. The installer includes the cross-compilers, OpenOCD, cmake_ and Ninja_ build tool, and a configuration tool called mconf-idf_. The installer can also download and run installers for Python_ 3.7 and `Git For Windows`_ if they are not already installed on the computer.

View file

@ -1 +1,36 @@
.. include:: ../../../en/api-reference/storage/nvs_flash.rst .. include:: ../../../../components/nvs_flash/README_CN.rst
NVS 分区生成程序
------------------
NVS 分区生成程序帮助生成 NVS 分区二进制文件,可使用烧录程序将二进制文件单独烧录至特定分区。烧录至分区上的键值对由 CSV 文件提供,详情请参考 :doc:`NVS 分区生成程序 <nvs_partition_gen>`
应用示例
-------------------
ESP-IDF :example:`storage` 目录下提供了两个代码示例:
:example:`storage/nvs_rw_value`
演示如何读取及写入 NVS 单个整数值。
此示例中的值表示 ESP32 模组重启次数。NVS 中数据不会因为模组重启而丢失,因此只有将这一值存储于 NVS 中,才能起到重启次数计数器的作用。
该示例也演示了如何检测读取/写入操作是否成功,以及某个特定值是否在 NVS 中尚未初始化。诊断程序以纯文本形式提供,帮助您追踪程序流程,及时发现问题。
:example:`storage/nvs_rw_blob` 
演示如何读取及写入 NVS 单个整数值和 Blob二进制大对象并在 NVS 中存储这一数值,即便 ESP32 模组重启也不会消失。
* value - 记录 ESP32 模组软重启次数和硬重启次数。
* blob - 内含记录模组运行次数的表格。此表格将被从 NVS 读取至动态分配的 RAM 上。每次手动软重启后,表格内运行次数即增加一次,新加的运行次数被写入 NVS。下拉 GPIO0 即可手动软重启。
该示例也演示了如何执行诊断程序以检测读取/写入操作是否成功。
API 参考
-------------
.. include:: /_build/inc/nvs_flash.inc
.. include:: /_build/inc/nvs.inc

View file

@ -1 +1,47 @@
.. include:: ../../../en/api-reference/storage/spi_flash.rst .. include:: ../../../../components/spi_flash/README_CN.rst
另请参考
------------
- :doc:`分区表 <../../api-guides/partition-tables>`
- :doc:`OTA API <../system/ota>` 提供了高层 API 用于更新存储在 flash 中的 app 固件。
- :doc:`NVS API <nvs_flash>` 提供了结构化 API 用于存储 SPI flash 中的碎片数据。
.. _spi-flash-implementation-details:
实现细节
------------
必须确保操作期间,两个 CPU 均未从 flash 运行代码,实现细节如下:
- 单核模式下SDK 在执行 flash 操作前将禁用中断或调度算法。
- 双核模式下实现细节更为复杂SDK 需确保两个 CPU 均未运行 flash 代码。
如果有 SPI flash API 在 CPU APRO 或 APP上调用它使用 ``esp_ipc_call`` API 在 CPU B 上运行 ``spi_flash_op_block_func`` 函数。``esp_ipc_call`` API 在 CPU B 上唤醒一个高优先级任务,即运行 ``spi_flash_op_block_func`` 函数。运行该函数将禁用 CPU B 上的 cache并使用 ``s_flash_op_can_start`` 旗帜来标志 cache 已禁用。然后CPU A 上的任务也会禁用 cache 并继续执行 flash 操作。
执行 flash 操作时CPU A 和 CPU B 仍然可以执行中断操作。默认中断代码均存储于 RAM 中,如果新添加了中断分配 API则应添加一个标志位以请求在 flash 操作期间禁用该新分配的中断。
Flash 操作完成后CPU A 上的函数将设置另一标志位,即 ``s_flash_op_complete``,用以通知 CPU B 上的任务可以重新启用 cache 并释放 CPU。接着CPU A 上的函数也重新启用 cache并将控制权返还给调用者。
另外,所有 API 函数均受互斥量 ``s_flash_op_mutex`` 保护。
在单核环境中(启用 :ref:`CONFIG_FREERTOS_UNICORE`),您需要禁用上述两个 cache 以防发生 CPU 间通信。
SPI Flash API 参考
-------------------------
.. include:: /_build/inc/esp_flash_spi_init.inc
.. include:: /_build/inc/esp_flash.inc
.. include:: /_build/inc/spi_flash_types.inc
分区表 API 参考
-------------------------------
.. include:: /_build/inc/esp_partition.inc
Flash 加密 API 参考
-----------------------------
.. include:: /_build/inc/esp_flash_encrypt.inc

View file

@ -1 +1,15 @@
.. include:: ../../../en/api-reference/storage/vfs.rst .. include:: ../../../../components/vfs/README_CN.rst
应用示例
-------------------
`指南`_ (未完成)
.. _指南: ../../template.html
API 参考
-------------
.. include:: /_build/inc/esp_vfs.inc
.. include:: /_build/inc/esp_vfs_dev.inc

View file

@ -32,7 +32,7 @@
#include "mesh/mesh.h" #include "mesh/mesh.h"
static const char *tag = "NimBLE_MESH"; static const char *tag = "NimBLE_MESH";
void ble_store_ram_init(void); void ble_store_config_init(void);
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG)) #define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG))
@ -418,6 +418,7 @@ void blemesh_host_task(void *param)
health_pub_init(); health_pub_init();
nimble_port_run(); nimble_port_run();
nimble_port_freertos_deinit();
} }
void app_main(void) void app_main(void)
@ -438,7 +439,7 @@ void app_main(void)
bt_mesh_register_gatt(); bt_mesh_register_gatt();
/* XXX Need to have template for store */ /* XXX Need to have template for store */
ble_store_ram_init(); ble_store_config_init();
nimble_port_freertos_init(blemesh_host_task); nimble_port_freertos_init(blemesh_host_task);
} }

View file

@ -221,9 +221,9 @@ static void start(void)
.queue_size = 20 .queue_size = 20
}; };
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
/* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */ /* dm9051 ethernet driver is based on spi driver */
mac_config.spi_hdl = spi_handle; eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
s_mac = esp_eth_mac_new_dm9051(&mac_config); s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
s_phy = esp_eth_phy_new_dm9051(&phy_config); s_phy = esp_eth_phy_new_dm9051(&phy_config);
#endif #endif
esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy); esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);

View file

@ -104,9 +104,9 @@ void app_main(void)
.queue_size = 20 .queue_size = 20
}; };
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
/* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */ /* dm9051 ethernet driver is based on spi driver */
mac_config.spi_hdl = spi_handle; eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
#endif #endif
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);

View file

@ -176,9 +176,9 @@ static void initialize_ethernet(void)
.queue_size = 20 .queue_size = 20
}; };
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
/* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */ /* dm9051 ethernet driver is based on spi driver */
mac_config.spi_hdl = spi_handle; eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
#endif #endif
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);

View file

@ -215,9 +215,9 @@ void register_ethernet(void)
.queue_size = 20 .queue_size = 20
}; };
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
/* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */ /* dm9051 ethernet driver is based on spi driver */
mac_config.spi_hdl = spi_handle; eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
#endif #endif
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);

View file

@ -0,0 +1,13 @@
# Connect to a running instance of OpenOCD
target remote 127.0.0.1:3333
# Reset and halt the target
mon reset halt
# Run to a specific point in ROM code,
# where most of initialization is complete.
thb *0x40007901
c
# Load the application into RAM
load
# Run till app_main
tb app_main
c

View file

@ -0,0 +1,129 @@
import os
import pexpect
import serial
import sys
import threading
import time
try:
import IDF
except ImportError:
test_fw_path = os.getenv('TEST_FW_PATH')
if test_fw_path and test_fw_path not in sys.path:
sys.path.insert(0, test_fw_path)
import IDF
import Utility
class CustomProcess(object):
def __init__(self, cmd, logfile):
self.f = open(logfile, 'wb')
self.p = pexpect.spawn(cmd, timeout=60, logfile=self.f)
def __enter__(self):
return self
def close(self):
self.p.terminate(force=True)
def __exit__(self, type, value, traceback):
self.close()
self.f.close()
class OCDProcess(CustomProcess):
def __init__(self, proj_path):
cmd = 'openocd -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg'
log_file = os.path.join(proj_path, 'openocd.log')
super(OCDProcess, self).__init__(cmd, log_file)
i = self.p.expect_exact(['Info : Listening on port 3333 for gdb connections', 'Error:'])
if i == 0:
Utility.console_log('openocd is listening for gdb connections')
else:
raise RuntimeError('openocd initialization has failed')
def close(self):
try:
self.p.sendcontrol('c')
self.p.expect_exact('shutdown command invoked')
except Exception:
Utility.console_log('openocd needs to be killed', 'O')
super(OCDProcess, self).close()
class GDBProcess(CustomProcess):
def __init__(self, proj_path, elf_path):
cmd = 'xtensa-esp32-elf-gdb -x {} --directory={} {}'.format(os.path.join(proj_path, '.gdbinit.ci'),
os.path.join(proj_path, 'main'),
elf_path)
log_file = os.path.join(proj_path, 'gdb.log')
super(GDBProcess, self).__init__(cmd, log_file)
self.p.sendline('') # it is for "---Type <return> to continue, or q <return> to quit---"
i = self.p.expect_exact(['Thread 1 hit Temporary breakpoint 2, app_main ()',
'Load failed'])
if i == 0:
Utility.console_log('gdb is at breakpoint')
else:
raise RuntimeError('Load failed: probably the ELF file was not built for loading with gdb')
self.p.expect_exact('(gdb)')
def close(self):
try:
self.p.sendline('q')
self.p.expect_exact('Quit anyway? (y or n)')
self.p.sendline('y')
self.p.expect_exact('Ending remote debugging.')
except Exception:
Utility.console_log('gdb needs to be killed', 'O')
super(GDBProcess, self).close()
def break_till_end(self):
self.p.sendline('b esp_restart')
self.p.sendline('c')
self.p.expect_exact('Thread 1 hit Breakpoint 3, esp_restart ()')
class SerialThread(object):
def run(self, log_path, exit_event):
with serial.Serial('/dev/ttyUSB1', 115200) as ser, open(log_path, 'wb') as f:
while True:
f.write(ser.read(ser.in_waiting))
if exit_event.is_set():
break
time.sleep(1)
def __init__(self, log_path):
self.exit_event = threading.Event()
self.t = threading.Thread(target=self.run, args=(log_path, self.exit_event,))
self.t.start()
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.exit_event.set()
self.t.join(60)
if self.t.is_alive():
Utility.console_log('The pyserial thread is still alive', 'O')
@IDF.idf_example_test(env_tag="test_jtag_arm")
def test_examples_loadable_elf(env, extra_data):
idf_path = os.environ['IDF_PATH']
rel_project_path = os.path.join('examples', 'get-started', 'hello_world')
proj_path = os.path.join(idf_path, rel_project_path)
elf_path = os.path.join(IDF.Example(rel_project_path).get_binary_path(rel_project_path), 'hello-world.elf')
esp_log_path = os.path.join(proj_path, 'esp.log')
with SerialThread(esp_log_path):
with OCDProcess(proj_path), GDBProcess(proj_path, elf_path) as gdb:
gdb.break_till_end()
if pexpect.run('grep "Restarting now." {}'.format(esp_log_path), withexitstatus=True)[1]:
raise RuntimeError('Expected output from ESP was not received')
if __name__ == '__main__':
test_examples_loadable_elf()

View file

@ -0,0 +1,6 @@
CONFIG_APP_BUILD_TYPE_ELF_RAM=y
CONFIG_VFS_SUPPORT_TERMIOS=
CONFIG_NEWLIB_NANO_FORMAT=y
CONFIG_ESP32_PANIC_PRINT_HALT=y
CONFIG_ESP32_DEBUG_STUBS_ENABLE=
CONFIG_ESP_ERR_TO_NAME_LOOKUP=

View file

@ -0,0 +1,27 @@
from __future__ import print_function
import os
import sys
try:
import IDF
except ImportError:
test_fw_path = os.getenv('TEST_FW_PATH')
if test_fw_path and test_fw_path not in sys.path:
sys.path.insert(0, test_fw_path)
import IDF
@IDF.idf_example_test(env_tag='Example_ExtFlash')
def test_examples_storage_ext_flash_fatfs(env, extra_data):
dut = env.get_dut('ext_flash_fatfs', 'examples/storage/ext_flash_fatfs')
dut.start_app()
dut.expect('Initialized external Flash')
dut.expect('partition \'nvs\'')
dut.expect('partition \'storage\'')
dut.expect('File written')
dut.expect('Read from file: \'Written using ESP-IDF')
if __name__ == '__main__':
test_examples_storage_ext_flash_fatfs()

View file

@ -30,6 +30,7 @@ const char *base_path = "/extflash";
static esp_flash_t* example_init_ext_flash(void); static esp_flash_t* example_init_ext_flash(void);
static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label); static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label);
static void example_list_data_partitions(void);
static bool example_mount_fatfs(const char* partition_label); static bool example_mount_fatfs(const char* partition_label);
static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes); static void example_get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes);
@ -45,6 +46,9 @@ void app_main(void)
const char *partition_label = "storage"; const char *partition_label = "storage";
example_add_partition(flash, partition_label); example_add_partition(flash, partition_label);
// List the available partitions
example_list_data_partitions();
// Initialize FAT FS in the partition // Initialize FAT FS in the partition
if (!example_mount_fatfs(partition_label)) { if (!example_mount_fatfs(partition_label)) {
return; return;
@ -139,6 +143,20 @@ static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, cons
return fat_partition; return fat_partition;
} }
static void example_list_data_partitions(void)
{
ESP_LOGI(TAG, "Listing data partitions:");
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);
for (; it != NULL; it = esp_partition_next(it)) {
const esp_partition_t *part = esp_partition_get(it);
ESP_LOGI(TAG, "- partition '%s', subtype %d, offset 0x%x, size %d kB",
part->label, part->subtype, part->address, part->size / 1024);
}
esp_partition_iterator_release(it);
}
static bool example_mount_fatfs(const char* partition_label) static bool example_mount_fatfs(const char* partition_label)
{ {
ESP_LOGI(TAG, "Mounting FAT filesystem"); ESP_LOGI(TAG, "Mounting FAT filesystem");

View file

@ -7,7 +7,7 @@ LDGEN_LIBRARIES=$(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(lib
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
define ldgen_process_template define ldgen_process_template
$(BUILD_DIR_BASE)/ldgen_libraries: $(LDGEN_LIBRARIES) $(IDF_PATH)/make/ldgen.mk $(BUILD_DIR_BASE)/ldgen_libraries: $(LDGEN_LIBRARIES) $(IDF_PATH)/make/ldgen.mk
printf "$(foreach info,$(LDGEN_LIBRARIES),$(subst \,/,$(shell cygpath -w $(info)))\n)" > $(BUILD_DIR_BASE)/ldgen_libraries printf "$(foreach info,$(LDGEN_LIBRARIES),$(subst \,/,$(shell cygpath -m $(info)))\n)" > $(BUILD_DIR_BASE)/ldgen_libraries
$(2): $(1) $(LDGEN_FRAGMENT_FILES) $(SDKCONFIG) $(BUILD_DIR_BASE)/ldgen_libraries $(2): $(1) $(LDGEN_FRAGMENT_FILES) $(SDKCONFIG) $(BUILD_DIR_BASE)/ldgen_libraries
@echo 'Generating $(notdir $(2))' @echo 'Generating $(notdir $(2))'
@ -18,8 +18,8 @@ $(2): $(1) $(LDGEN_FRAGMENT_FILES) $(SDKCONFIG) $(BUILD_DIR_BASE)/ldgen_librarie
--libraries-file $(BUILD_DIR_BASE)/ldgen_libraries \ --libraries-file $(BUILD_DIR_BASE)/ldgen_libraries \
--output $(2) \ --output $(2) \
--kconfig $(IDF_PATH)/Kconfig \ --kconfig $(IDF_PATH)/Kconfig \
--env "COMPONENT_KCONFIGS=$(foreach k, $(COMPONENT_KCONFIGS), $(shell cygpath -w $(k)))" \ --env "COMPONENT_KCONFIGS=$(foreach k, $(COMPONENT_KCONFIGS), $(shell cygpath -m $(k)))" \
--env "COMPONENT_KCONFIGS_PROJBUILD=$(foreach k, $(COMPONENT_KCONFIGS_PROJBUILD), $(shell cygpath -w $(k)))" \ --env "COMPONENT_KCONFIGS_PROJBUILD=$(foreach k, $(COMPONENT_KCONFIGS_PROJBUILD), $(shell cygpath -m $(k)))" \
--env "IDF_CMAKE=n" \ --env "IDF_CMAKE=n" \
--objdump $(OBJDUMP) --objdump $(OBJDUMP)
endef endef

View file

@ -320,9 +320,15 @@ ifndef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
endif endif
@echo "To flash app & partition table, run 'make flash' or:" @echo "To flash app & partition table, run 'make flash' or:"
else else
ifdef CONFIG_APP_BUILD_GENERATE_BINARIES
@echo "To flash all build output, run 'make flash' or:" @echo "To flash all build output, run 'make flash' or:"
endif endif
endif
ifdef CONFIG_APP_BUILD_GENERATE_BINARIES
@echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) @echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
else
@echo "Binary is not available for flashing"
endif
# If we have `version.txt` then prefer that for extracting IDF version # If we have `version.txt` then prefer that for extracting IDF version
@ -533,6 +539,7 @@ $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp
$(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP)
app: $(APP_BIN) partition_table_get_info app: $(APP_BIN) partition_table_get_info
ifeq ("$(CONFIG_APP_BUILD_GENERATE_BINARIES)","y")
ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image
@echo "App built but not signed. Signing step via espsecure.py:" @echo "App built but not signed. Signing step via espsecure.py:"
@echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)" @echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)"
@ -542,6 +549,9 @@ else
@echo "App built. Default flash app command is:" @echo "App built. Default flash app command is:"
@echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN) @echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN)
endif endif
else
@echo "Application in not built and cannot be flashed."
endif
all_binaries: $(APP_BIN) all_binaries: $(APP_BIN)

View file

@ -7,9 +7,9 @@ COMPONENT_SDKCONFIG_RENAMES := $(foreach component,$(COMPONENT_PATHS),$(wildcard
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
# kconfiglib requires Windows-style paths for kconfig files # kconfiglib requires Windows-style paths for kconfig files
COMPONENT_KCONFIGS := $(shell cygpath -w $(COMPONENT_KCONFIGS)) COMPONENT_KCONFIGS := $(shell cygpath -m $(COMPONENT_KCONFIGS))
COMPONENT_KCONFIGS_PROJBUILD := $(shell cygpath -w $(COMPONENT_KCONFIGS_PROJBUILD)) COMPONENT_KCONFIGS_PROJBUILD := $(shell cygpath -m $(COMPONENT_KCONFIGS_PROJBUILD))
COMPONENT_SDKCONFIG_RENAMES := $(shell cygpath -w $(COMPONENT_SDKCONFIG_RENAMES)) COMPONENT_SDKCONFIG_RENAMES := $(shell cygpath -m $(COMPONENT_SDKCONFIG_RENAMES))
endif endif
#For doing make menuconfig etc #For doing make menuconfig etc

View file

@ -388,19 +388,5 @@ build_installer:
- build_cmdlinerunner - build_cmdlinerunner
before_script: [] before_script: []
script: script:
- mkdir idf_tools_tmp
- export IDF_TOOLS_PATH=$PWD/idf_tools_tmp
- tools/idf_tools.py --non-interactive download --platform Windows-x86_64 all
- tools/idf_tools.py --tools-json tools/windows/tool_setup/tools_fallback.json --non-interactive download --platform Windows-x86_64 all
- mkdir tools/windows/tool_setup/dist
- mv idf_tools_tmp/dist/* tools/windows/tool_setup/dist/
- cd tools/windows/tool_setup/ - cd tools/windows/tool_setup/
- mkdir unzip - ./build_installer.sh
- cd unzip
- wget --no-verbose https://www.7-zip.org/a/7z1900-extra.7z
- 7zr e -y 7z1900-extra.7z
- cd ..
- wget --no-verbose https://dl.espressif.com/dl/esp-idf/idf_versions.txt
- iscc idf_tool_setup.iss

View file

@ -203,6 +203,25 @@ example_test_008:
- ESP32 - ESP32
- Example_Flash_Encryption - Example_Flash_Encryption
example_test_009:
extends: .example_test_template
tags:
- ESP32
- test_jtag_arm
artifacts:
when: always
paths:
- $CI_PROJECT_DIR/examples/get-started/hello_world/*.log
expire_in: 1 week
variables:
SETUP_TOOLS: "1"
example_test_010:
extends: .example_test_template
tags:
- ESP32
- Example_ExtFlash
UT_001: UT_001:
extends: .unit_test_template extends: .unit_test_template
parallel: 50 parallel: 50
@ -432,6 +451,20 @@ UT_032:
- ESP32_IDF - ESP32_IDF
- UT_T1_FlashEncryption - UT_T1_FlashEncryption
UT_032:
extends: .unit_test_template
parallel: 4
tags:
- ESP32_IDF
- UT_T2_Ethernet
UT_033:
extends: .unit_test_template
tags:
- ESP32_IDF
- UT_T2_Ethernet
- psram
nvs_compatible_test: nvs_compatible_test:
extends: .test_template extends: .test_template
artifacts: artifacts:

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