Merge branch 'master' into feature/cmake

This commit is contained in:
Angus Gratton 2018-09-05 10:35:04 +08:00 committed by Angus Gratton
commit b355854d4d
137 changed files with 4236 additions and 1175 deletions

View File

@ -4,6 +4,7 @@ stages:
- host_test
- unit_test
- integration_test
- check
- deploy
variables:
@ -68,6 +69,12 @@ before_script:
# fetch the submodules (& if necessary re-fetch repo) from gitlab
- time ./tools/ci/get-full-sources.sh
# used for check scripts which we want to run unconditionally
.do_nothing_before_no_filter:
before_script: &do_nothing_before_no_filter
- *git_clean_stale_submodules
# used for everything else where we want to do no prep, except for bot filter
.do_nothing_before:
before_script: &do_nothing_before
- *git_clean_stale_submodules
@ -534,30 +541,22 @@ check_doc_links:
- make linkcheck
check_line_endings:
stage: deploy
stage: check
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- build
except:
- master
- /^release\/v/
- /^v\d+\.\d+(\.\d+)?($|-)/
dependencies: []
before_script: *do_nothing_before
before_script: *do_nothing_before_no_filter
script:
- tools/ci/check-line-endings.sh ${IDF_PATH}
check_commit_msg:
stage: deploy
stage: check
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- build
except:
- master
- /^release\/v/
- /^v\d+\.\d+(\.\d+)?($|-)/
dependencies: []
before_script: *do_nothing_before
before_script: *do_nothing_before_no_filter
script:
- git status
- git log -n10 --oneline
@ -565,16 +564,12 @@ check_commit_msg:
- 'git log --pretty=%s master.. -- | grep "^WIP: " && exit 1 || exit 0'
check_permissions:
stage: deploy
stage: check
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- build
except:
- master
- /^release\/v/
- /^v\d+\.\d+(\.\d+)?($|-)/
dependencies: []
before_script: *do_nothing_before
before_script: *do_nothing_before_no_filter
script:
- tools/ci/check-executable.sh
@ -593,18 +588,14 @@ check_examples_cmake_make:
- tools/ci/check_examples_cmake_make.sh
check_submodule_sync:
stage: deploy
stage: check
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- build
except:
- master
- /^release\/v/
- /^v\d+\.\d+(\.\d+)?($|-)/
dependencies: []
variables:
GIT_STRATEGY: clone
before_script: *do_nothing_before
before_script: *do_nothing_before_no_filter
script:
# check if all submodules are correctly synced to public repostory
- git submodule update --init --recursive

View File

@ -49,7 +49,7 @@ $(BLANK_OTA_DATA_FILE): partition_table_get_info
blank_ota_data: $(BLANK_OTA_DATA_FILE)
erase_ota: partition_table_get_info check_python_dependencies
erase_ota: partition_table_get_info | check_python_dependencies
@echo $(if $(OTA_DATA_OFFSET), "Erase ota_data [addr=$(OTA_DATA_OFFSET) size=$(OTA_DATA_SIZE)] ...", $(error "ERROR: Partition table does not have ota_data partition."))
$(ESPTOOLPY_SERIAL) erase_region $(OTA_DATA_OFFSET) $(OTA_DATA_SIZE)

View File

@ -377,7 +377,7 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)
return ESP_ERR_OTA_VALIDATE_FAILED;
}
#ifdef CONFIG_SECURE_BOOT_ENABLED
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len);
if (ret != ESP_OK) {
return ESP_ERR_OTA_VALIDATE_FAILED;

View File

@ -127,14 +127,96 @@ config BOOTLOADER_HOLD_TIME_GPIO
The GPIO must be held low continuously for this period of time after reset
before a factory reset or test partition boot (as applicable) is performed.
config BOOTLOADER_WDT_ENABLE
bool "Use RTC watchdog in start code"
default y
help
Tracks the execution time of startup code.
If the execution time is exceeded, the RTC_WDT will restart system.
It is also useful to prevent a lock up in start code caused by an unstable power source.
NOTE: Tracks the execution time starts from the bootloader code - re-set timeout, while selecting the source for slow_clk - and ends calling app_main.
Re-set timeout is needed due to WDT uses a SLOW_CLK clock source. After changing a frequency slow_clk a time of WDT needs to re-set for new frequency.
slow_clk depends on ESP32_RTC_CLOCK_SOURCE (INTERNAL_RC or EXTERNAL_CRYSTAL).
config BOOTLOADER_WDT_DISABLE_IN_USER_CODE
bool "Allows RTC watchdog disable in user code"
depends on BOOTLOADER_WDT_ENABLE
default n
help
If it is set, the client must itself reset or disable rtc_wdt in their code (app_main()).
Otherwise rtc_wdt will be disabled before calling app_main function.
Use function rtc_wdt_feed() for resetting counter of rtc_wdt.
Use function rtc_wdt_disable() for disabling rtc_wdt.
config BOOTLOADER_WDT_TIME_MS
int "Timeout for RTC watchdog (ms)"
depends on BOOTLOADER_WDT_ENABLE
default 9000
range 0 120000
help
Verify that this parameter is correct and more then the execution time.
Pay attention to options such as reset to factory, trigger test partition and encryption on boot
- these options can increase the execution time.
Note: RTC_WDT will reset while encryption operations will be performed.
endmenu # Bootloader
menu "Security features"
# These three are the actual options to check in code,
# selected by the displayed options
config SECURE_SIGNED_ON_BOOT
bool
default y
depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
config SECURE_SIGNED_ON_UPDATE
bool
default y
depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
config SECURE_SIGNED_APPS
bool
default y
depends on SECURE_SIGNED_ON_BOOT || SECURE_SIGNED_ON_UPDATE
config SECURE_SIGNED_APPS_NO_SECURE_BOOT
bool "Require signed app images"
default n
depends on !SECURE_BOOT_ENABLED
help
Require apps to be signed to verify their integrity.
This option uses the same app signature scheme as hardware secure boot, but unlike hardware secure boot it does not prevent the bootloader from being physically updated. This means that the device can be secured against remote network access, but not physical access. Compared to using hardware Secure Boot this option is much simpler to implement.
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
bool "Bootloader verifies app signatures"
default n
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT
help
If this option is set, the bootloader will be compiled with code to verify that an app is signed before booting it.
If hardware secure boot is enabled, this option is always enabled and cannot be disabled.
If hardware secure boot is not enabled, this option doesn't add significant security by itself so most users will want to leave it disabled.
config SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
bool "Verify app signature on update"
default y
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT
help
If this option is set, any OTA updated apps will have the signature verified before being considered valid.
When enabled, the signature is automatically checked whenever the esp_ota_ops.h APIs are used for OTA updates,
or esp_image_format.h APIs are used to verify apps.
If hardware secure boot is enabled, this option is always enabled and cannot be disabled.
If hardware secure boot is not enabled, this option still adds significant security against network-based attackers by preventing spoofing of OTA updates.
config SECURE_BOOT_ENABLED
bool "Enable secure boot in bootloader (READ DOCS FIRST)"
default N
bool "Enable hardware secure boot in bootloader (READ DOCS FIRST)"
default n
help
Build a bootloader which enables secure boot on first boot.
@ -169,12 +251,12 @@ endchoice
config SECURE_BOOT_BUILD_SIGNED_BINARIES
bool "Sign binaries during build"
depends on SECURE_BOOT_ENABLED
depends on SECURE_SIGNED_APPS
default y
help
Once secure boot is enabled, bootloader will only boot if partition table and app image are signed.
Once secure boot or signed app requirement is enabled, app images are required to be signed.
If enabled, these binary files are signed as part of the build process. The file named in "Secure boot private signing key" will be used to sign the image.
If enabled (default), these binary files are signed as part of the build process. The file named in "Secure boot private signing key" will be used to sign the image.
If disabled, unsigned app/partition data will be built. They must be signed manually using espsecure.py (for example, on a remote signing server.)
@ -183,7 +265,7 @@ config SECURE_BOOT_SIGNING_KEY
depends on SECURE_BOOT_BUILD_SIGNED_BINARIES
default secure_boot_signing_key.pem
help
Path to the key file used to sign partition tables and app images for secure boot. Once secure boot is enabled, bootloader will only boot if partition table and app image are signed.
Path to the key file used to sign app images.
Key file is an ECDSA private key (NIST256p curve) in PEM format.
@ -196,11 +278,11 @@ config SECURE_BOOT_SIGNING_KEY
config SECURE_BOOT_VERIFICATION_KEY
string "Secure boot public signature verification key"
depends on SECURE_BOOT_ENABLED && !SECURE_BOOT_BUILD_SIGNED_BINARIES
depends on SECURE_SIGNED_APPS && !SECURE_BOOT_BUILD_SIGNED_BINARIES
default signature_verification_key.bin
help
Path to a public key file used to verify signed images. This key is compiled into the bootloader,
and may also be used to verify signatures on OTA images after download.
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.
Key file is in raw binary format, and can be extracted from a
PEM formatted private key using the espsecure.py

View File

@ -56,7 +56,7 @@ bootloader: $(BOOTLOADER_BIN) | check_python_dependencies
ESPTOOL_ALL_FLASH_ARGS += $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)
bootloader-flash: $(BOOTLOADER_BIN) $(call prereq_if_explicit,erase_flash) check_python_dependencies
bootloader-flash: $(BOOTLOADER_BIN) $(call prereq_if_explicit,erase_flash) | check_python_dependencies
$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^
else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH

View File

@ -36,11 +36,12 @@ SECTIONS
{
. = ALIGN (16);
_stext = .;
_text_start = ABSOLUTE(.);
_loader_text_start = ABSOLUTE(.);
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
*liblog.a:(.literal .text .literal.* .text.*)
*libgcc.a:(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_common.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
@ -56,7 +57,7 @@ SECTIONS
*(.fini.literal)
*(.fini)
*(.gnu.version)
_text_end = ABSOLUTE(.);
_loader_text_end = ABSOLUTE(.);
_etext = .;
} > iram_loader_seg

View File

@ -12,7 +12,7 @@ COMPONENT_SRCDIRS := src
#
# Secure boot signing key support
#
ifdef CONFIG_SECURE_BOOT_ENABLED
ifdef CONFIG_SECURE_SIGNED_APPS
# this path is created relative to the component build directory
SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin)

View File

@ -85,6 +85,8 @@ static inline /** @cond */ IRAM_ATTR /** @endcond */ bool esp_flash_encryption_e
* @note Take care not to power off the device while this function
* is running, or the partition currently being encrypted will be lost.
*
* @note RTC_WDT will reset while encryption operations will be performed (if RTC_WDT is configured).
*
* @return ESP_OK if all operations succeeded, ESP_ERR_INVALID_STATE
* if a fatal error occured during encryption of all partitions.
*/
@ -93,6 +95,7 @@ esp_err_t esp_flash_encrypt_check_and_update(void);
/** @brief Encrypt-in-place a block of flash sectors
*
* @note This function resets RTC_WDT between operations with sectors.
* @param src_addr Source offset in flash. Should be multiple of 4096 bytes.
* @param data_length Length of data to encrypt in bytes. Will be rounded up to next multiple of 4096 bytes.
*

View File

@ -17,6 +17,14 @@
#include <esp_err.h>
#include "soc/efuse_reg.h"
#include "sdkconfig.h"
#ifdef CONFIG_SECURE_BOOT_ENABLED
#if !defined(CONFIG_SECURE_SIGNED_ON_BOOT) || !defined(CONFIG_SECURE_SIGNED_ON_UPDATE) || !defined(CONFIG_SECURE_SIGNED_APPS)
#error "internal sdkconfig error, secure boot should always enable all signature options"
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -21,6 +21,7 @@
#include "esp_spi_flash.h"
#define FLASH_SECTOR_SIZE 0x1000
#define FLASH_BLOCK_SIZE 0x10000
/* Provide a Flash API for bootloader_support code,
that can be used from bootloader or app code.
@ -100,4 +101,14 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
*/
esp_err_t bootloader_flash_erase_sector(size_t sector);
/**
* @brief Erase the Flash range.
*
* @param start_addr start address of flash offset
* @param size sector aligned size to be erased
*
* @return esp_err_t
*/
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size);
#endif

View File

@ -106,8 +106,8 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat
partitions = bootloader_mmap(ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
if (!partitions) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
return false;
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
return false;
}
ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_OFFSET, (intptr_t)partitions);
@ -128,7 +128,7 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat
// partition->label is not null-terminated string.
strncpy(label, (char *)&partition->label, sizeof(label) - 1);
if (fl_ota_data_erase == true || (bootloader_common_label_search(list_erase, label) == true)) {
err = esp_rom_spiflash_erase_area(partition->pos.offset, partition->pos.size);
err = bootloader_flash_erase_range(partition->pos.offset, partition->pos.size);
if (err != ESP_OK) {
ret = false;
marker = "err";

View File

@ -73,6 +73,11 @@ esp_err_t bootloader_flash_erase_sector(size_t sector)
return spi_flash_erase_sector(sector);
}
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
{
return spi_flash_erase_range(start_addr, size);
}
#else
/* Bootloader version, uses ROM functions only */
#include <soc/dport_reg.h>
@ -247,4 +252,28 @@ esp_err_t bootloader_flash_erase_sector(size_t sector)
return spi_to_esp_err(esp_rom_spiflash_erase_sector(sector));
}
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
{
if (start_addr % FLASH_SECTOR_SIZE != 0) {
return ESP_ERR_INVALID_ARG;
}
if (size % FLASH_SECTOR_SIZE != 0) {
return ESP_ERR_INVALID_SIZE;
}
size_t start = start_addr / FLASH_SECTOR_SIZE;
size_t end = start + size / FLASH_SECTOR_SIZE;
const size_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE;
esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK;
for (size_t sector = start; sector != end && rc == ESP_ROM_SPIFLASH_RESULT_OK; ) {
if (sector % sectors_per_block == 0 && end - sector >= sectors_per_block) {
rc = esp_rom_spiflash_erase_block(sector / sectors_per_block);
sector += sectors_per_block;
} else {
rc = esp_rom_spiflash_erase_sector(sector);
++sector;
}
}
return spi_to_esp_err(rc);
}
#endif

View File

@ -143,8 +143,21 @@ static esp_err_t bootloader_main()
ESP_LOGI(TAG, "compile time " __TIME__ );
ets_set_appcpu_boot_addr(0);
#ifdef CONFIG_BOOTLOADER_WDT_ENABLE
ESP_LOGD(TAG, "Enabling RTCWDT(%d ms)", CONFIG_BOOTLOADER_WDT_TIME_MS);
rtc_wdt_protect_off();
rtc_wdt_disable();
rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us);
rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us);
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS);
rtc_wdt_enable();
rtc_wdt_protect_on();
#else
/* disable watch dog here */
rtc_wdt_disable();
#endif
REG_SET_FIELD(TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY, TIMG_WDT_WKEY_VALUE);
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH

View File

@ -23,19 +23,23 @@
#ifndef BOOTLOADER_BUILD
#include "esp_system.h"
#endif
void bootloader_fill_random(void *buffer, size_t length)
{
return esp_fill_random(buffer, length);
}
#else
void bootloader_fill_random(void *buffer, size_t length)
{
uint8_t *buffer_bytes = (uint8_t *)buffer;
uint32_t random;
#ifdef BOOTLOADER_BUILD
uint32_t start, now;
#endif
assert(buffer != NULL);
for (int i = 0; i < length; i++) {
if (i == 0 || i % 4 == 0) { /* redundant check is for a compiler warning */
#ifdef BOOTLOADER_BUILD
/* in bootloader with ADC feeding HWRNG, we accumulate 1
bit of entropy per 40 APB cycles (==80 CPU cycles.)
@ -49,14 +53,12 @@ void bootloader_fill_random(void *buffer, size_t length)
random ^= REG_READ(WDEV_RND_REG);
RSR(CCOUNT, now);
} while(now - start < 80*32*2); /* extra factor of 2 is precautionary */
#else
random = esp_random();
#endif
}
buffer_bytes[i] = random >> ((i % 4) * 8);
}
}
#endif // BOOTLOADER_BUILD
void bootloader_random_enable(void)
{

View File

@ -24,6 +24,20 @@
#include <bootloader_random.h>
#include <bootloader_sha.h>
/* Checking signatures as part of verifying images is necessary:
- Always if secure boot is enabled
- Differently in bootloader and/or app, depending on kconfig
*/
#ifdef BOOTLOADER_BUILD
#ifdef CONFIG_SECURE_SIGNED_ON_BOOT
#define SECURE_BOOT_CHECK_SIGNATURE
#endif
#else /* !BOOTLOADER_BUILD */
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
#define SECURE_BOOT_CHECK_SIGNATURE
#endif
#endif
static const char *TAG = "esp_image";
#define HASH_LEN 32 /* SHA-256 digest length */
@ -107,7 +121,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
}
// Calculate SHA-256 of image if secure boot is on, or if image has a hash appended
#ifdef CONFIG_SECURE_BOOT_ENABLED
#ifdef SECURE_BOOT_CHECK_SIGNATURE
if (1) {
#else
if (data->image.hash_appended) {
@ -174,7 +188,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
rewritten the header - rely on esptool.py having verified the bootloader at flashing time, instead.
*/
if (!is_bootloader) {
#ifdef CONFIG_SECURE_BOOT_ENABLED
#ifdef SECURE_BOOT_CHECK_SIGNATURE
// secure boot images have a signature appended
err = verify_secure_boot_signature(sha_handle, data);
#else
@ -182,7 +196,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
if (sha_handle != NULL && !esp_cpu_in_ocd_debug_mode()) {
err = verify_simple_hash(sha_handle, data);
}
#endif // CONFIG_SECURE_BOOT_ENABLED
#endif // SECURE_BOOT_CHECK_SIGNATURE
} else { // is_bootloader
// bootloader may still have a sha256 digest handle open
if (sha_handle != NULL) {
@ -519,6 +533,8 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
{
uint8_t image_hash[HASH_LEN] = { 0 };
ESP_LOGI(TAG, "Verifying image signature...");
// For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash
// appended to the image for corruption detection
if (data->image.hash_appended) {

View File

@ -24,6 +24,7 @@
#include "esp_efuse.h"
#include "esp_log.h"
#include "rom/secure_boot.h"
#include "soc/rtc_wdt.h"
#include "rom/cache.h"
#include "rom/spi_flash.h" /* TODO: Remove this */
@ -317,6 +318,7 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
}
for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
rtc_wdt_feed();
uint32_t sec_start = i + src_addr;
err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false);
if (err != ESP_OK) {

View File

@ -116,7 +116,7 @@ typedef union {
struct a2d_audio_cfg_param {
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
esp_a2d_mcc_t mcc; /*!< A2DP media codec capability information */
} audio_cfg; /*!< media codec configuration infomation */
} audio_cfg; /*!< media codec configuration information */
/**
* @brief ESP_A2D_MEDIA_CTRL_ACK_EVT
@ -147,12 +147,12 @@ typedef void (* esp_a2d_sink_data_cb_t)(const uint8_t *buf, uint32_t len);
/**
* @brief A2DP source data read callback function
*
* @param[in] buf : buffer to be filled with PCM data stream from higer layer
* @param[in] buf : buffer to be filled with PCM data stream from higher layer
*
* @param[in] len : size(in bytes) of data block to be copied to buf. -1 is an indication to user
* that data buffer shall be flushed
*
* @return size of bytes read successfully, if the argumetn len is -1, this value is ignored.
* @return size of bytes read successfully, if the argument len is -1, this value is ignored.
*
*/
typedef int32_t (* esp_a2d_source_data_cb_t)(uint8_t *buf, int32_t len);

View File

@ -111,7 +111,7 @@ typedef enum {
/// AVRC shuffle modes
typedef enum {
ESP_AVRC_PS_SHUFFLE_OFF = 0x1, /*<! shuffle off */
ESP_AVRC_PS_SHUFFLE_ALL = 0x2, /*<! all trackes shuffle */
ESP_AVRC_PS_SHUFFLE_ALL = 0x2, /*<! shuffle all tracks */
ESP_AVRC_PS_SHUFFLE_GROUP = 0x3 /*<! group shuffle */
} esp_avrc_ps_shf_value_ids_t;

View File

@ -112,7 +112,7 @@ typedef enum {
BLE_ADDR_TYPE_RPA_RANDOM = 0x03,
} esp_ble_addr_type_t;
/// Used to exchange the encrytyption key in the init key & response key
/// Used to exchange the encryption key in the init key & response key
#define ESP_BLE_ENC_KEY_MASK (1 << 0) /* relate to BTM_BLE_ENC_KEY_MASK in stack/btm_api.h */
/// Used to exchange the IRK key in the init key & response key
#define ESP_BLE_ID_KEY_MASK (1 << 1) /* relate to BTM_BLE_ID_KEY_MASK in stack/btm_api.h */

View File

@ -151,7 +151,7 @@ typedef enum {
ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT, /*!< When stop scan complete, the event comes */
ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT, /*!< When set the static rand address complete, the event comes */
ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT, /*!< When update connection parameters complete, the event comes */
ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT, /*!< When set pkt lenght complete, the event comes */
ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT, /*!< When set pkt length complete, the event comes */
ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT, /*!< When Enable/disable privacy on the local device complete, the event comes */
ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT, /*!< When remove the bond device complete, the event comes */
ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT, /*!< When clear the bond device clear complete, the event comes */
@ -455,7 +455,7 @@ typedef union
} esp_ble_key_value_t; /*!< ble key value type*/
/**
* @brief struct type of the bond key informatuon value
* @brief struct type of the bond key information value
*/
typedef struct
{
@ -508,7 +508,7 @@ typedef struct
uint8_t fail_reason; /*!< The HCI reason/error code for when success=FALSE */
esp_ble_addr_type_t addr_type; /*!< Peer device address type */
esp_bt_dev_type_t dev_type; /*!< Device type */
} esp_ble_auth_cmpl_t; /*!< The ble authentication complite cb type */
} esp_ble_auth_cmpl_t; /*!< The ble authentication complete cb type */
/**
* @brief union associated with ble security
@ -520,7 +520,7 @@ typedef union
esp_ble_key_t ble_key; /*!< BLE SMP keys used when pairing */
esp_ble_local_id_keys_t ble_id_keys; /*!< BLE IR event */
esp_ble_auth_cmpl_t auth_cmpl; /*!< Authentication complete indication. */
} esp_ble_sec_t; /*!< Ble secutity type */
} esp_ble_sec_t; /*!< BLE security type */
/// Sub Event of ESP_GAP_BLE_SCAN_RESULT_EVT
typedef enum {
@ -1023,10 +1023,10 @@ esp_err_t esp_ble_gap_security_rsp(esp_bd_addr_t bd_addr, bool accept);
esp_err_t esp_ble_set_encryption(esp_bd_addr_t bd_addr, esp_ble_sec_act_t sec_act);
/**
* @brief Reply the key value to the peer device in the lagecy connection stage.
* @brief Reply the key value to the peer device in the legacy connection stage.
*
* @param[in] bd_addr : BD address of the peer
* @param[in] accept : passkey entry sucessful or declined.
* @param[in] accept : passkey entry successful or declined.
* @param[in] passkey : passkey value, must be a 6 digit number,
* can be lead by 0.
*
@ -1038,7 +1038,7 @@ esp_err_t esp_ble_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t pas
/**
* @brief Reply the comfirm value to the peer device in the lagecy connection stage.
* @brief Reply the confirm value to the peer device in the legacy connection stage.
*
* @param[in] bd_addr : BD address of the peer device
* @param[in] accept : numbers to compare are the same or different.
@ -1091,7 +1091,7 @@ esp_err_t esp_ble_get_bond_device_list(int *dev_num, esp_ble_bond_dev_t *dev_lis
/**
* @brief This function is to disconnect the physical connection of the peer device
* gattc maybe have multiple virtual GATT server connections when multiple app_id registed.
* gattc may have multiple virtual GATT server connections when multiple app_id registered.
* esp_ble_gattc_close (esp_gatt_if_t gattc_if, uint16_t conn_id) only close one virtual GATT server connection.
* if there exist other virtual GATT server connections, it does not disconnect the physical connection.
* esp_ble_gap_disconnect(esp_bd_addr_t remote_device) disconnect the physical connection directly.

View File

@ -70,7 +70,7 @@ typedef enum {
typedef struct {
esp_bt_gap_dev_prop_type_t type; /*!< device property type */
int len; /*!< device property value length */
void *val; /*!< devlice prpoerty value */
void *val; /*!< device property value */
} esp_bt_gap_dev_prop_t;
/// Extended Inquiry Response data type
@ -97,7 +97,7 @@ typedef enum {
ESP_BT_COD_SRVC_RENDERING = 0x20, /*!< Rendering, e.g. Printing, Speakers */
ESP_BT_COD_SRVC_CAPTURING = 0x40, /*!< Capturing, e.g. Scanner, Microphone */
ESP_BT_COD_SRVC_OBJ_TRANSFER = 0x80, /*!< Object Transfer, e.g. v-Inbox, v-Folder */
ESP_BT_COD_SRVC_AUDIO = 0x100, /*!< Audio, e.g. Speaker, Microphone, Headerset service */
ESP_BT_COD_SRVC_AUDIO = 0x100, /*!< Audio, e.g. Speaker, Microphone, Headset service */
ESP_BT_COD_SRVC_TELEPHONY = 0x200, /*!< Telephony, e.g. Cordless telephony, Modem, Headset service */
ESP_BT_COD_SRVC_INFORMATION = 0x400, /*!< Information, e.g., WEB-server, WAP-server */
} esp_bt_cod_srvc_t;
@ -188,7 +188,7 @@ typedef union {
esp_bd_addr_t bda; /*!< remote bluetooth device address*/
int num_prop; /*!< number of properties got */
esp_bt_gap_dev_prop_t *prop; /*!< properties discovered from the new device */
} disc_res; /*!< discovery result paramter struct */
} disc_res; /*!< discovery result parameter struct */
/**
* @brief ESP_BT_GAP_DISC_STATE_CHANGED_EVT
@ -506,7 +506,7 @@ esp_err_t esp_bt_gap_set_security_param(esp_bt_sp_param_t param_type,
* @brief Reply the key value to the peer device in the legacy connection stage.
*
* @param[in] bd_addr : BD address of the peer
* @param[in] accept : passkey entry sucessful or declined.
* @param[in] accept : passkey entry successful or declined.
* @param[in] passkey : passkey value, must be a 6 digit number,
* can be lead by 0.
*

View File

@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_GATT_COMMON_API_H__
#define __ESP_GATT_COMMON_API_H__
#include <stdint.h>
#include <stdbool.h>
@ -44,3 +47,5 @@ extern esp_err_t esp_ble_gatt_set_local_mtu (uint16_t mtu);
#ifdef __cplusplus
}
#endif
#endif /* __ESP_GATT_COMMON_API_H__ */

View File

@ -224,7 +224,7 @@ typedef enum {
ESP_GATT_CONN_L2C_FAILURE = 1, /*!< General L2cap failure */ /* relate to BTA_GATT_CONN_L2C_FAILURE in bta/bta_gatt_api.h */
ESP_GATT_CONN_TIMEOUT = 0x08, /*!< Connection timeout */ /* relate to BTA_GATT_CONN_TIMEOUT in bta/bta_gatt_api.h */
ESP_GATT_CONN_TERMINATE_PEER_USER = 0x13, /*!< Connection terminate by peer user */ /* relate to BTA_GATT_CONN_TERMINATE_PEER_USER in bta/bta_gatt_api.h */
ESP_GATT_CONN_TERMINATE_LOCAL_HOST = 0x16, /*!< Connectionterminated by local host */ /* relate to BTA_GATT_CONN_TERMINATE_LOCAL_HOST in bta/bta_gatt_api.h */
ESP_GATT_CONN_TERMINATE_LOCAL_HOST = 0x16, /*!< Connection terminated by local host */ /* relate to BTA_GATT_CONN_TERMINATE_LOCAL_HOST in bta/bta_gatt_api.h */
ESP_GATT_CONN_FAIL_ESTABLISH = 0x3e, /*!< Connection fail to establish */ /* relate to BTA_GATT_CONN_FAIL_ESTABLISH in bta/bta_gatt_api.h */
ESP_GATT_CONN_LMP_TIMEOUT = 0x22, /*!< Connection fail for LMP response tout */ /* relate to BTA_GATT_CONN_LMP_TIMEOUT in bta/bta_gatt_api.h */
ESP_GATT_CONN_CONN_CANCEL = 0x0100, /*!< L2CAP connection cancelled */ /* relate to BTA_GATT_CONN_CONN_CANCEL in bta/bta_gatt_api.h */
@ -453,7 +453,7 @@ typedef struct {
uint16_t incl_srvc_s_handle; /*!< The start handle of the service which has been included */
uint16_t incl_srvc_e_handle; /*!< The end handle of the service which has been included */
esp_bt_uuid_t uuid; /*!< The include service uuid */
} esp_gattc_incl_svc_elem_t; /*!< The gattc inclue service element */
} esp_gattc_incl_svc_elem_t; /*!< The gattc include service element */
#ifdef __cplusplus

View File

@ -312,7 +312,7 @@ esp_err_t esp_ble_gattc_open(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, e
/**
* @brief Close a virtual connection to a GATT server. gattc maybe have multiple virtual GATT server connections when multiple app_id registed,
* @brief Close the virtual connection to the GATT server. gattc may have multiple virtual GATT server connections when multiple app_id registered,
* this API only close one virtual GATT server connection. if there exist other virtual GATT server connections,
* it does not disconnect the physical connection.
* if you want to disconnect the physical connection directly, you can use esp_ble_gap_disconnect(esp_bd_addr_t remote_device).
@ -371,7 +371,7 @@ esp_err_t esp_ble_gattc_search_service(esp_gatt_if_t gattc_if, uint16_t conn_id,
* @param[in] gattc_if: Gatt client access interface.
* @param[in] conn_id: connection ID which identify the server.
* @param[in] svc_uuid: the pointer to the service uuid.
* @param[out] result: The pointer to the service whith has been found in the gattc cache.
* @param[out] result: The pointer to the service which has been found in the gattc cache.
* @param[inout] count: input the number of service want to find,
* it will output the number of service has been found in the gattc cache with the given service uuid.
* @param[in] offset: Offset of the service position to get.
@ -392,7 +392,7 @@ esp_gatt_status_t esp_ble_gattc_get_service(esp_gatt_if_t gattc_if, uint16_t con
* @param[in] conn_id: connection ID which identify the server.
* @param[in] start_handle: the attribute start handle.
* @param[in] end_handle: the attribute end handle
* @param[out] result: The pointer to the charateristic in the service.
* @param[out] result: The pointer to the characteristic in the service.
* @param[inout] count: input the number of characteristic want to find,
* it will output the number of characteristic has been found in the gattc cache with the given service.
* @param[in] offset: Offset of the characteristic position to get.
@ -695,7 +695,7 @@ esp_err_t esp_ble_gattc_write_char_descr (esp_gatt_if_t gattc_if,
*
* @param[in] gattc_if: Gatt client access interface.
* @param[in] conn_id : connection ID.
* @param[in] handle : charateristic handle to prepare write.
* @param[in] handle : characteristic handle to prepare write.
* @param[in] offset : offset of the write value.
* @param[in] value_len: length of the value to be written.
* @param[in] value : the value to be written.
@ -720,7 +720,7 @@ esp_err_t esp_ble_gattc_prepare_write(esp_gatt_if_t gattc_if,
*
* @param[in] gattc_if: Gatt client access interface.
* @param[in] conn_id : connection ID.
* @param[in] handle : characteristic descriptor hanlde to prepare write.
* @param[in] handle : characteristic descriptor handle to prepare write.
* @param[in] offset : offset of the write value.
* @param[in] value_len: length of the value to be written.
* @param[in] value : the value to be written.

View File

@ -40,7 +40,7 @@ typedef enum {
ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED = 0, /*!< audio connection released */
ESP_HF_CLIENT_AUDIO_STATE_CONNECTING, /*!< audio connection has been initiated */
ESP_HF_CLIENT_AUDIO_STATE_CONNECTED, /*!< audio connection is established */
ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC, /*!< mSBC audio connection is estalibshed */
ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC, /*!< mSBC audio connection is established */
} esp_hf_client_audio_state_t;
/// in-band ring tone state
@ -66,9 +66,9 @@ typedef enum {
#define ESP_HF_CLIENT_CHLD_FEAT_REL_ACC 0x02 /* 1 Release active calls and accept other waiting or held call */
#define ESP_HF_CLIENT_CHLD_FEAT_REL_X 0x04 /* 1x Release specified active call only */
#define ESP_HF_CLIENT_CHLD_FEAT_HOLD_ACC 0x08 /* 2 Active calls on hold and accept other waiting or held call */
#define ESP_HF_CLIENT_CHLD_FEAT_PRIV_X 0x10 /* 2x Request private mode with specified call(put the rest on hold */
#define ESP_HF_CLIENT_CHLD_FEAT_PRIV_X 0x10 /* 2x Request private mode with specified call(put the rest on hold) */
#define ESP_HF_CLIENT_CHLD_FEAT_MERGE 0x20 /* 3 Add held call to multiparty */
#define ESP_HF_CLIENT_CHLD_FEAT_MERGE_DETACH 0x40 /* 4 Connect two calls and leave(disconnct from multiparty */
#define ESP_HF_CLIENT_CHLD_FEAT_MERGE_DETACH 0x40 /* 4 Connect two calls and leave(disconnect from multiparty) */
/// HF CLIENT callback events
typedef enum {
@ -140,7 +140,7 @@ typedef union {
* @brief ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT
*/
struct hf_client_signal_strength_ind_param {
int value; /*!< singal strength value, ranges from 0 to 5 */
int value; /*!< signal strength value, ranges from 0 to 5 */
} signal_strength; /*!< HF callback param of ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT */
/**
@ -175,7 +175,7 @@ typedef union {
* @brief ESP_HF_CLIENT_CIND_CALL_HELD_EVT
*/
struct hf_client_call_held_ind_param {
esp_hf_call_held_status_t status; /*!< bluetooth proprietary call hold status indocator */
esp_hf_call_held_status_t status; /*!< bluetooth proprietary call hold status indicator */
} call_held; /*!< HF callback param of ESP_HF_CLIENT_CIND_CALL_HELD_EVT */
/**
@ -619,7 +619,7 @@ void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t c
* @brief Down sampling utility to convert high sampling rate into 8K/16bits 1-channel mode PCM
* samples. This can only be used in the case that Voice Over HCI is enabled.
*
* @param[in] src: pointer to the buffer where the original smapling PCM are stored
* @param[in] src: pointer to the buffer where the original sampling PCM are stored
* @param[in] in_bytes: length of the input PCM sample buffer in byte
* @param[in] dst: pointer to the buffer which is to be used to store the converted PCM samples
*

View File

@ -120,7 +120,7 @@ typedef enum {
/// response indication codes for AT commands
typedef enum {
ESP_HF_AT_RESPONSE_CODE_OK = 0, /*!< acknoweledges execution of a command line */
ESP_HF_AT_RESPONSE_CODE_OK = 0, /*!< acknowledges execution of a command line */
ESP_HF_AT_RESPONSE_CODE_ERR, /*!< command not accepted */
ESP_HF_AT_RESPONSE_CODE_NO_CARRIER, /*!< connection terminated */
ESP_HF_AT_RESPONSE_CODE_BUSY, /*!< busy signal detected */

View File

@ -62,9 +62,9 @@ typedef enum {
ESP_SPP_CLOSE_EVT = 27, /*!< When SPP connection closed, the event comes */
ESP_SPP_START_EVT = 28, /*!< When SPP server started, the event comes */
ESP_SPP_CL_INIT_EVT = 29, /*!< When SPP client initiated a connection, the event comes */
ESP_SPP_DATA_IND_EVT = 30, /*!< When SPP connection received data, the event comes, olny for ESP_SPP_MODE_CB */
ESP_SPP_CONG_EVT = 31, /*!< When SPP connection congestion status changed, the event comes, olny for ESP_SPP_MODE_CB */
ESP_SPP_WRITE_EVT = 33, /*!< When SPP write operation completes, the event comes, olny for ESP_SPP_MODE_CB */
ESP_SPP_DATA_IND_EVT = 30, /*!< When SPP connection received data, the event comes, only for ESP_SPP_MODE_CB */
ESP_SPP_CONG_EVT = 31, /*!< When SPP connection congestion status changed, the event comes, only for ESP_SPP_MODE_CB */
ESP_SPP_WRITE_EVT = 33, /*!< When SPP write operation completes, the event comes, only for ESP_SPP_MODE_CB */
ESP_SPP_SRV_OPEN_EVT = 34, /*!< When SPP Server connection open, the event comes */
} esp_spp_cb_event_t;
@ -95,7 +95,7 @@ typedef union {
struct spp_open_evt_param {
esp_spp_status_t status; /*!< status */
uint32_t handle; /*!< The connection handle */
int fd; /*!< The file descriptor olny for ESP_SPP_MODE_VFS*/
int fd; /*!< The file descriptor only for ESP_SPP_MODE_VFS */
esp_bd_addr_t rem_bda; /*!< The peer address */
} open; /*!< SPP callback param of ESP_SPP_OPEN_EVT */
@ -106,7 +106,7 @@ typedef union {
esp_spp_status_t status; /*!< status */
uint32_t handle; /*!< The connection handle */
uint32_t new_listen_handle; /*!< The new listen handle */
int fd; /*!< The file descriptor olny for ESP_SPP_MODE_VFS*/
int fd; /*!< The file descriptor only for ESP_SPP_MODE_VFS */
esp_bd_addr_t rem_bda; /*!< The peer address */
} srv_open; /*!< SPP callback param of ESP_SPP_SRV_OPEN_EVT */
/**
@ -155,7 +155,7 @@ typedef union {
esp_spp_status_t status; /*!< status */
uint32_t handle; /*!< The connection handle */
uint16_t len; /*!< The length of data */
uint8_t *data; /*!< The data recived */
uint8_t *data; /*!< The data received */
} data_ind; /*!< SPP callback param of ESP_SPP_DATA_IND_EVT */
/**
@ -224,14 +224,14 @@ esp_err_t esp_spp_deinit();
esp_err_t esp_spp_start_discovery(esp_bd_addr_t bd_addr);
/**
* @brief This function makes an SPP conection to a remote BD Address.
* @brief This function makes an SPP connection to a remote BD Address.
* When the connection is initiated or failed to initiate,
* the callback is called with ESP_SPP_CL_INIT_EVT.
* When the connection is established or failed,
* the callback is called with ESP_SPP_OPEN_EVT.
*
* @param[in] sec_mask: Security Setting Mask .
* @param[in] role: Msater or slave.
* @param[in] role: Master or slave.
* @param[in] remote_scn: Remote device bluetooth device SCN.
* @param[in] peer_bd_addr: Remote device bluetooth device address.
*
@ -262,7 +262,7 @@ esp_err_t esp_spp_disconnect(uint32_t handle);
* with ESP_SPP_SRV_OPEN_EVT.
*
* @param[in] sec_mask: Security Setting Mask .
* @param[in] role: Msater or slave.
* @param[in] role: Master or slave.
* @param[in] local_scn: The specific channel you want to get.
* If channel is 0, means get any channel.
* @param[in] name: Server's name.
@ -276,7 +276,7 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
/**
* @brief This function is used to write data, olny for ESP_SPP_MODE_CB.
* @brief This function is used to write data, only for ESP_SPP_MODE_CB.
*
* @param[in] handle: The connection handle.
* @param[in] len: The length of the data written.
@ -302,4 +302,4 @@ esp_err_t esp_spp_vfs_register(void);
}
#endif
#endif ///__ESP_SPP_API_H__
#endif ///__ESP_SPP_API_H__

View File

@ -65,6 +65,23 @@ static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p)
p_cb->set_local_privacy_cback = NULL;
}
if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_ENABLE){
BTM_TRACE_DEBUG("Advertise with new resolvable private address, now.");
/**
* Restart advertising, using new resolvable private address
*/
btm_ble_stop_adv();
btm_ble_start_adv();
}
if (btm_cb.ble_ctr_cb.inq_var.state == BTM_BLE_SCANNING){
BTM_TRACE_DEBUG("Scan with new resolvable private address, now.");
/**
* Restart scaning, using new resolvable private address
*/
btm_ble_stop_scan();
btm_ble_start_scan();
}
/* start a periodical timer to refresh random addr */
btu_stop_timer_oneshot(&p_cb->raddr_timer_ent);
#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)

View File

@ -23,6 +23,7 @@
******************************************************************************/
#include <stddef.h>
#include <string.h>
#include "common/bt_target.h"
#include "stack/rfcdefs.h"
#include "stack/port_api.h"
@ -513,6 +514,13 @@ void rfc_send_test (tRFC_MCB *p_mcb, BOOLEAN is_command, BT_HDR *p_buf)
UINT16 xx;
UINT8 *p_src, *p_dest;
BT_HDR *p_buf_new;
if ((p_buf_new = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE)) == NULL) {
return;
}
memcpy(p_buf_new, p_buf, sizeof(BT_HDR) + p_buf->offset + p_buf->len);
osi_free(p_buf);
p_buf = p_buf_new;
/* Shift buffer to give space for header */
if (p_buf->offset < (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2)) {
p_src = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len - 1;

View File

@ -354,15 +354,17 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
type = *p++;
p = sdpu_get_len_from_type (p, type, &list_len);
}
if (list_len && list_len < cpy_len ) {
if (list_len < cpy_len ) {
cpy_len = list_len;
}
#if (SDP_DEBUG_RAW == TRUE)
SDP_TRACE_WARNING("list_len :%d cpy_len:%d raw_size:%d raw_used:%d\n",
SDP_TRACE_DEBUG("list_len :%d cpy_len:%d raw_size:%d raw_used:%d\n",
list_len, cpy_len, p_ccb->p_db->raw_size, p_ccb->p_db->raw_used);
#endif
memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
p_ccb->p_db->raw_used += cpy_len;
if (cpy_len != 0){
memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
p_ccb->p_db->raw_used += cpy_len;
}
}
}
#endif

View File

@ -820,17 +820,30 @@ static void btdm_controller_mem_init(void)
{
/* initialise .data section */
memcpy(&_data_start_btdm, (void *)_data_start_btdm_rom, &_data_end_btdm - &_data_start_btdm);
ESP_LOGD(BTDM_LOG_TAG, ".data initialise [0x%08x] <== [0x%08x]\n", (uint32_t)&_data_start_btdm, _data_start_btdm_rom);
ESP_LOGD(BTDM_LOG_TAG, ".data initialise [0x%08x] <== [0x%08x]", (uint32_t)&_data_start_btdm, _data_start_btdm_rom);
//initial em, .bss section
for (int i = 1; i < sizeof(btdm_dram_available_region)/sizeof(btdm_dram_available_region_t); i++) {
if (btdm_dram_available_region[i].mode != ESP_BT_MODE_IDLE) {
memset((void *)btdm_dram_available_region[i].start, 0x0, btdm_dram_available_region[i].end - btdm_dram_available_region[i].start);
ESP_LOGD(BTDM_LOG_TAG, ".bss initialise [0x%08x] - [0x%08x]\n", btdm_dram_available_region[i].start, btdm_dram_available_region[i].end);
ESP_LOGD(BTDM_LOG_TAG, ".bss initialise [0x%08x] - [0x%08x]", btdm_dram_available_region[i].start, btdm_dram_available_region[i].end);
}
}
}
static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end)
{
int ret = heap_caps_add_region(start, end);
/* heap_caps_add_region() returns ESP_ERR_INVALID_SIZE if the memory region is
* is too small to fit a heap. This cannot be termed as a fatal error and hence
* we replace it by ESP_OK
*/
if (ret == ESP_ERR_INVALID_SIZE) {
return ESP_OK;
}
return ret;
}
esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode)
{
bool update = true;
@ -870,14 +883,14 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode)
&& mem_end == btdm_dram_available_region[i+1].start) {
continue;
} else {
ESP_LOGD(BTDM_LOG_TAG, "Release DRAM [0x%08x] - [0x%08x]\n", mem_start, mem_end);
ESP_ERROR_CHECK(heap_caps_add_region(mem_start, mem_end));
ESP_LOGD(BTDM_LOG_TAG, "Release DRAM [0x%08x] - [0x%08x]", mem_start, mem_end);
ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end));
update = true;
}
} else {
mem_end = btdm_dram_available_region[i].end;
ESP_LOGD(BTDM_LOG_TAG, "Release DRAM [0x%08x] - [0x%08x]\n", mem_start, mem_end);
ESP_ERROR_CHECK(heap_caps_add_region(mem_start, mem_end));
ESP_LOGD(BTDM_LOG_TAG, "Release DRAM [0x%08x] - [0x%08x]", mem_start, mem_end);
ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end));
update = true;
}
}
@ -886,14 +899,14 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode)
mem_start = (intptr_t)&_btdm_bss_start;
mem_end = (intptr_t)&_btdm_bss_end;
if (mem_start != mem_end) {
ESP_LOGD(BTDM_LOG_TAG, "Release BTDM BSS [0x%08x] - [0x%08x]\n", mem_start, mem_end);
ESP_ERROR_CHECK(heap_caps_add_region(mem_start, mem_end));
ESP_LOGD(BTDM_LOG_TAG, "Release BTDM BSS [0x%08x] - [0x%08x]", mem_start, mem_end);
ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end));
}
mem_start = (intptr_t)&_btdm_data_start;
mem_end = (intptr_t)&_btdm_data_end;
if (mem_start != mem_end) {
ESP_LOGD(BTDM_LOG_TAG, "Release BTDM Data [0x%08x] - [0x%08x]\n", mem_start, mem_end);
ESP_ERROR_CHECK(heap_caps_add_region(mem_start, mem_end));
ESP_LOGD(BTDM_LOG_TAG, "Release BTDM Data [0x%08x] - [0x%08x]", mem_start, mem_end);
ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end));
}
}
return ESP_OK;
@ -913,14 +926,14 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode)
mem_start = (intptr_t)&_bt_bss_start;
mem_end = (intptr_t)&_bt_bss_end;
if (mem_start != mem_end) {
ESP_LOGD(BTDM_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x]\n", mem_start, mem_end);
ESP_ERROR_CHECK(heap_caps_add_region(mem_start, mem_end));
ESP_LOGD(BTDM_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x]", mem_start, mem_end);
ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end));
}
mem_start = (intptr_t)&_bt_data_start;
mem_end = (intptr_t)&_bt_data_end;
if (mem_start != mem_end) {
ESP_LOGD(BTDM_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x]\n", mem_start, mem_end);
ESP_ERROR_CHECK(heap_caps_add_region(mem_start, mem_end));
ESP_LOGD(BTDM_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x]", mem_start, mem_end);
ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end));
}
}
return ESP_OK;
@ -976,7 +989,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
}
#endif
ESP_LOGI(BTDM_LOG_TAG, "BT controller compile version [%s]\n", btdm_controller_get_compile_version());
ESP_LOGI(BTDM_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version());
#if CONFIG_SPIRAM_USE_MALLOC
btdm_queue_table_mux = xSemaphoreCreateMutex();

View File

@ -141,7 +141,7 @@ typedef struct {
* It will be overwrite with a constant value which in menuconfig or from a macro.
* So, do not modify the value when esp_bt_controller_init()
*/
uint8_t bt_max_sync_conn; /*!< BR/EDR maxium ACL connection numbers. Effective in menuconfig */
uint8_t bt_max_sync_conn; /*!< BR/EDR maximum ACL connection numbers. Effective in menuconfig */
uint32_t magic; /*!< Magic number */
} esp_bt_controller_config_t;
@ -233,7 +233,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type);
* BR/EDR power control will use the power in range of minimum value and maximum value.
* The power level will effect the global BR/EDR TX power, such inquire, page, connection and so on.
* Please call the function after esp_bt_controller_enable and before any function which cause RF do TX.
* So you can call the function can before do discover, beofre profile init and so on.
* So you can call the function before doing discovery, profile init and so on.
* For example, if you want BR/EDR use the new TX power to do inquire, you should call
* this function before inquire. Another word, If call this function when BR/EDR is in inquire(ING),
* please do inquire again after call this function.
@ -324,7 +324,7 @@ bool esp_vhci_host_check_send_available(void);
void esp_vhci_host_send_packet(uint8_t *data, uint16_t len);
/** @brief esp_vhci_host_register_callback
* register the vhci referece callback, the call back
* register the vhci reference callback
* struct defined by vhci_host_callback structure.
* @param callback esp_vhci_host_callback type variable
* @return ESP_OK - success, ESP_FAIL - failed
@ -440,7 +440,7 @@ bool esp_bt_controller_is_sleeping(void);
* Note that after this request, bluetooth controller may again enter sleep as long as the modem sleep is enabled
*
* Profiling shows that it takes several milliseconds to wakeup from modem sleep after this request.
* Generally it takes longer if 32kHz XTAL is used than the main XTAL, due to the lower frequncy of the former as the bluetooth low power clock source.
* Generally it takes longer if 32kHz XTAL is used than the main XTAL, due to the lower frequency of the former as the bluetooth low power clock source.
*/
void esp_bt_controller_wakeup_request(void);

@ -1 +1 @@
Subproject commit 17e29e6ed4e2c952a24e4097e9f41bb89bac6128
Subproject commit c272133d6d9c046e05e2514b12e17cc561980865

View File

@ -20,6 +20,7 @@
#include "esp_types.h"
#include "esp_log.h"
#include "esp_intr_alloc.h"
#include "esp_pm.h"
#include "soc/dport_reg.h"
#include "soc/can_struct.h"
#include "driver/gpio.h"
@ -128,6 +129,10 @@ typedef struct {
SemaphoreHandle_t alert_semphr;
uint32_t alerts_enabled;
uint32_t alerts_triggered;
#ifdef CONFIG_PM_ENABLE
//Power Management
esp_pm_lock_handle_t pm_lock;
#endif
} can_obj_t;
static can_obj_t *p_can_obj = NULL;
@ -591,6 +596,7 @@ static void can_configure_gpio(gpio_num_t tx, gpio_num_t rx, gpio_num_t clkout,
gpio_set_pull_mode(rx, GPIO_FLOATING);
gpio_matrix_in(rx, CAN_RX_IDX, false);
gpio_pad_select_gpio(rx);
gpio_set_direction(rx, GPIO_MODE_INPUT);
//Configure output clock pin (Optional)
if (clkout >= 0 && clkout < GPIO_NUM_MAX) {
@ -611,41 +617,61 @@ static void can_configure_gpio(gpio_num_t tx, gpio_num_t rx, gpio_num_t clkout,
esp_err_t can_driver_install(const can_general_config_t *g_config, const can_timing_config_t *t_config, const can_filter_config_t *f_config)
{
//Check arguments and state
CAN_CHECK(p_can_obj == NULL, ESP_ERR_INVALID_STATE); //Check is driver is already installed
//Check arguments
CAN_CHECK(g_config != NULL, ESP_ERR_INVALID_ARG);
CAN_CHECK(t_config != NULL, ESP_ERR_INVALID_ARG);
CAN_CHECK(f_config != NULL, ESP_ERR_INVALID_ARG);
CAN_CHECK(g_config->rx_queue_len > 0, ESP_ERR_INVALID_ARG);
CAN_CHECK(g_config->tx_io >= 0 && g_config->tx_io < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG);
CAN_CHECK(g_config->rx_io >= 0 && g_config->rx_io < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG);
esp_err_t ret;
//Initialize CAN object
p_can_obj = calloc(1, sizeof(can_obj_t));
CAN_CHECK(p_can_obj != NULL, ESP_ERR_NO_MEM);
p_can_obj->tx_queue = (g_config->tx_queue_len > 0) ? xQueueCreate(g_config->tx_queue_len, sizeof(can_frame_t)) : NULL;
p_can_obj->rx_queue = xQueueCreate(g_config->rx_queue_len, sizeof(can_frame_t));
p_can_obj->alert_semphr = xSemaphoreCreateBinary();
if ((g_config->tx_queue_len > 0 && p_can_obj->tx_queue == NULL) ||
p_can_obj->rx_queue == NULL || p_can_obj->alert_semphr == NULL) {
esp_err_t ret;
can_obj_t *p_can_obj_dummy;
//Create a CAN object
p_can_obj_dummy = calloc(1, sizeof(can_obj_t));
CAN_CHECK(p_can_obj_dummy != NULL, ESP_ERR_NO_MEM);
//Initialize queues, semaphores, and power management locks
p_can_obj_dummy->tx_queue = (g_config->tx_queue_len > 0) ? xQueueCreate(g_config->tx_queue_len, sizeof(can_frame_t)) : NULL;
p_can_obj_dummy->rx_queue = xQueueCreate(g_config->rx_queue_len, sizeof(can_frame_t));
p_can_obj_dummy->alert_semphr = xSemaphoreCreateBinary();
if ((g_config->tx_queue_len > 0 && p_can_obj_dummy->tx_queue == NULL) ||
p_can_obj_dummy->rx_queue == NULL || p_can_obj_dummy->alert_semphr == NULL) {
ret = ESP_ERR_NO_MEM;
goto err;
}
p_can_obj->control_flags = CTRL_FLAG_STOPPED;
p_can_obj->control_flags |= (g_config->mode == CAN_MODE_NO_ACK) ? CTRL_FLAG_SELF_TEST : 0;
p_can_obj->control_flags |= (g_config->mode == CAN_MODE_LISTEN_ONLY) ? CTRL_FLAG_LISTEN_ONLY : 0;
p_can_obj->tx_msg_count = 0;
p_can_obj->rx_msg_count = 0;
p_can_obj->tx_failed_count = 0;
p_can_obj->rx_missed_count = 0;
p_can_obj->arb_lost_count = 0;
p_can_obj->bus_error_count = 0;
p_can_obj->alerts_enabled = g_config->alerts_enabled;
p_can_obj->alerts_triggered = 0;
#ifdef CONFIG_PM_ENABLE
esp_err_t pm_err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "can", &(p_can_obj_dummy->pm_lock));
if (pm_err != ESP_OK ) {
ret = pm_err;
goto err;
}
#endif
//Initialize flags and variables
p_can_obj_dummy->control_flags = CTRL_FLAG_STOPPED;
p_can_obj_dummy->control_flags |= (g_config->mode == CAN_MODE_NO_ACK) ? CTRL_FLAG_SELF_TEST : 0;
p_can_obj_dummy->control_flags |= (g_config->mode == CAN_MODE_LISTEN_ONLY) ? CTRL_FLAG_LISTEN_ONLY : 0;
p_can_obj_dummy->tx_msg_count = 0;
p_can_obj_dummy->rx_msg_count = 0;
p_can_obj_dummy->tx_failed_count = 0;
p_can_obj_dummy->rx_missed_count = 0;
p_can_obj_dummy->arb_lost_count = 0;
p_can_obj_dummy->bus_error_count = 0;
p_can_obj_dummy->alerts_enabled = g_config->alerts_enabled;
p_can_obj_dummy->alerts_triggered = 0;
//Initialize CAN peripheral registers, and allocate interrupt
CAN_ENTER_CRITICAL();
//Initialize CAN peripheral
if (p_can_obj == NULL) {
p_can_obj = p_can_obj_dummy;
} else {
//Check if driver is already installed
CAN_EXIT_CRITICAL();
ret = ESP_ERR_INVALID_STATE;
goto err;
}
periph_module_enable(PERIPH_CAN_MODULE); //Enable APB CLK to CAN peripheral
configASSERT(can_enter_reset_mode() == ESP_OK); //Must enter reset mode to write to config registers
can_config_pelican(); //Use PeliCAN addresses
@ -661,56 +687,72 @@ esp_err_t can_driver_install(const can_general_config_t *g_config, const can_tim
can_configure_gpio(g_config->tx_io, g_config->rx_io, g_config->clkout_io, g_config->bus_off_io);
(void) can_get_interrupt_reason(); //Read interrupt reg to clear it before allocating ISR
ESP_ERROR_CHECK(esp_intr_alloc(ETS_CAN_INTR_SOURCE, 0, can_intr_handler_main, NULL, &p_can_obj->isr_handle));
CAN_EXIT_CRITICAL();
//Todo: Allow interrupt to be registered to specified CPU
CAN_EXIT_CRITICAL();
//CAN module is still in reset mode, users need to call can_start() afterwards
return ESP_OK;
#ifdef CONFIG_PM_ENABLE
ESP_ERROR_CHECK(esp_pm_lock_acquire(p_can_obj->pm_lock)); //Acquire pm_lock to keep APB clock at 80MHz
#endif
return ESP_OK; //CAN module is still in reset mode, users need to call can_start() afterwards
err:
//Cleanup and return error
if (p_can_obj != NULL) {
if (p_can_obj->tx_queue != NULL) {
vQueueDelete(p_can_obj->tx_queue);
p_can_obj->tx_queue = NULL;
//Cleanup CAN object and return error
if (p_can_obj_dummy != NULL) {
if (p_can_obj_dummy->tx_queue != NULL) {
vQueueDelete(p_can_obj_dummy->tx_queue);
p_can_obj_dummy->tx_queue = NULL;
}
if (p_can_obj->rx_queue != NULL) {
vQueueDelete(p_can_obj->rx_queue);
p_can_obj->rx_queue = NULL;
if (p_can_obj_dummy->rx_queue != NULL) {
vQueueDelete(p_can_obj_dummy->rx_queue);
p_can_obj_dummy->rx_queue = NULL;
}
if (p_can_obj->alert_semphr != NULL) {
vSemaphoreDelete(p_can_obj->alert_semphr);
p_can_obj->alert_semphr = NULL;
if (p_can_obj_dummy->alert_semphr != NULL) {
vSemaphoreDelete(p_can_obj_dummy->alert_semphr);
p_can_obj_dummy->alert_semphr = NULL;
}
free(p_can_obj);
#ifdef CONFIG_PM_ENABLE
if (p_can_obj_dummy->pm_lock != NULL) {
ESP_ERROR_CHECK(esp_pm_lock_delete(p_can_obj_dummy->pm_lock));
}
#endif
free(p_can_obj_dummy);
}
return ret;
}
esp_err_t can_driver_uninstall()
{
//Check state
can_obj_t *p_can_obj_dummy;
CAN_ENTER_CRITICAL();
//Check state
CAN_CHECK_FROM_CRIT(p_can_obj != NULL, ESP_ERR_INVALID_STATE);
CAN_CHECK_FROM_CRIT(p_can_obj->control_flags & (CTRL_FLAG_STOPPED | CTRL_FLAG_BUS_OFF), ESP_ERR_INVALID_STATE);
//Clear registers
configASSERT(can_enter_reset_mode() == ESP_OK); //Enter reset mode to stop any CAN bus activity
//Clear registers by reading
(void) can_get_interrupt_reason();
(void) can_get_arbitration_lost_capture();
(void) can_get_error_code_capture();
ESP_ERROR_CHECK(esp_intr_free(p_can_obj->isr_handle)); //Free interrupt
periph_module_disable(PERIPH_CAN_MODULE); //Disable CAN peripheral
//Delete queues, semaphores
if (p_can_obj->tx_queue != NULL) {
vQueueDelete(p_can_obj->tx_queue);
}
vQueueDelete(p_can_obj->rx_queue);
vSemaphoreDelete(p_can_obj->alert_semphr);
free(p_can_obj); //Free can driver object
p_can_obj_dummy = p_can_obj; //Use dummy to shorten critical section
p_can_obj = NULL;
CAN_EXIT_CRITICAL();
//Delete queues, semaphores, and power management locks
if (p_can_obj_dummy->tx_queue != NULL) {
vQueueDelete(p_can_obj_dummy->tx_queue);
}
vQueueDelete(p_can_obj_dummy->rx_queue);
vSemaphoreDelete(p_can_obj_dummy->alert_semphr);
#ifdef CONFIG_PM_ENABLE
//Release and delete power management lock
ESP_ERROR_CHECK(esp_pm_lock_release(p_can_obj_dummy->pm_lock));
ESP_ERROR_CHECK(esp_pm_lock_delete(p_can_obj_dummy->pm_lock));
#endif
free(p_can_obj_dummy); //Free can driver object
return ESP_OK;
}
@ -801,7 +843,7 @@ esp_err_t can_transmit(const can_message_t *message, TickType_t ticks_to_wait)
} else if (xQueueSend(p_can_obj->tx_queue, &tx_frame, ticks_to_wait) == pdTRUE) {
//Copied to TX Queue
CAN_ENTER_CRITICAL();
if (p_can_obj->control_flags & (CTRL_FLAG_STOPPED | CTRL_FLAG_STOPPED)) {
if (p_can_obj->control_flags & (CTRL_FLAG_STOPPED | CTRL_FLAG_BUS_OFF)) {
//TX queue was reset (due to stop/bus_off), remove copied frame from queue to prevent transmission
configASSERT(xQueueReceive(p_can_obj->tx_queue, &tx_frame, 0) == pdTRUE);
ret = ESP_ERR_INVALID_STATE;

View File

@ -42,6 +42,8 @@ extern "C" {
* @brief Initializer macros for timing configuration structure
*
* The following initializer macros offer commonly found bit rates.
*
* @note These timing values are based on the assumption APB clock is at 80MHz
*/
#define CAN_TIMING_CONFIG_25KBITS() {.brp = 128, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define CAN_TIMING_CONFIG_50KBITS() {.brp = 80, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}

View File

@ -646,6 +646,14 @@ config BROWNOUT_DET_LVL
default 7 if BROWNOUT_DET_LVL_SEL_7
#Reduce PHY TX power when brownout reset
config REDUCE_PHY_TX_POWER
bool "Reduce PHY TX power when brownout reset"
depends on BROWNOUT_DET
default y
help
When brownout reset occurs, reduce PHY TX power to keep the code running
# Note about the use of "FRC1" name: currently FRC1 timer is not used for
# high resolution timekeeping anymore. Instead the esp_timer API, implemented
# using FRC2 timer, is used.

View File

@ -26,6 +26,7 @@
#include "rom/rtc.h"
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/rtc_wdt.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/i2s_reg.h"
#include "driver/periph_ctrl.h"
@ -87,6 +88,18 @@ void esp_clk_init(void)
rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M);
#ifdef CONFIG_BOOTLOADER_WDT_ENABLE
// WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed.
// If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times.
// Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec).
// This prevents excessive delay before resetting in case the supply voltage is drawdown.
// (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec).
rtc_wdt_protect_off();
rtc_wdt_feed();
rtc_wdt_set_time(RTC_WDT_STAGE0, 1600);
rtc_wdt_protect_on();
#endif
#if defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL)
select_rtc_slow_clk(SLOW_CLK_32K_XTAL);
#elif defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC)
@ -97,6 +110,14 @@ void esp_clk_init(void)
select_rtc_slow_clk(RTC_SLOW_FREQ_RTC);
#endif
#ifdef CONFIG_BOOTLOADER_WDT_ENABLE
// After changing a frequency WDT timeout needs to be set for new frequency.
rtc_wdt_protect_off();
rtc_wdt_feed();
rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS);
rtc_wdt_protect_on();
#endif
rtc_cpu_freq_config_t old_config, new_config;
rtc_clk_cpu_freq_get_config(&old_config);
const uint32_t old_freq_mhz = old_config.freq_mhz;

View File

@ -137,7 +137,9 @@ void IRAM_ATTR call_start_cpu0()
|| rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET
#endif
) {
#ifndef CONFIG_BOOTLOADER_WDT_ENABLE
rtc_wdt_disable();
#endif
}
//Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
@ -427,9 +429,6 @@ static void do_global_ctors(void)
static void main_task(void* args)
{
// Now that the application is about to start, disable boot watchdogs
REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
rtc_wdt_disable();
#if !CONFIG_FREERTOS_UNICORE
// Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
while (port_xSchedulerRunning[1] == 0) {
@ -470,6 +469,10 @@ static void main_task(void* args)
}
#endif
// Now that the application is about to start, disable boot watchdog
#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE
rtc_wdt_disable();
#endif
app_main();
vTaskDelete(NULL);
}

View File

@ -16,6 +16,7 @@
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_clk.h"
#include "soc/wdev_reg.h"
@ -54,3 +55,16 @@ uint32_t IRAM_ATTR esp_random(void)
last_ccount = ccount;
return result ^ REG_READ(WDEV_RND_REG);
}
void esp_fill_random(void *buf, size_t len)
{
assert(buf != NULL);
uint8_t *buf_bytes = (uint8_t *)buf;
while (len > 0) {
uint32_t word = esp_random();
uint32_t to_copy = MIN(sizeof(word), len);
memcpy(buf_bytes, &word, to_copy);
buf_bytes += to_copy;
len -= to_copy;
}
}

View File

@ -27,20 +27,20 @@ typedef int32_t esp_err_t;
#define ESP_OK 0 /*!< esp_err_t value indicating success (no error) */
#define ESP_FAIL -1 /*!< Generic esp_err_t code indicating failure */
#define ESP_ERR_NO_MEM 0x101 /*!< Out of memory */
#define ESP_ERR_INVALID_ARG 0x102 /*!< Invalid argument */
#define ESP_ERR_INVALID_STATE 0x103 /*!< Invalid state */
#define ESP_ERR_INVALID_SIZE 0x104 /*!< Invalid size */
#define ESP_ERR_NOT_FOUND 0x105 /*!< Requested resource not found */
#define ESP_ERR_NOT_SUPPORTED 0x106 /*!< Operation or feature not supported */
#define ESP_ERR_TIMEOUT 0x107 /*!< Operation timed out */
#define ESP_ERR_NO_MEM 0x101 /*!< Out of memory */
#define ESP_ERR_INVALID_ARG 0x102 /*!< Invalid argument */
#define ESP_ERR_INVALID_STATE 0x103 /*!< Invalid state */
#define ESP_ERR_INVALID_SIZE 0x104 /*!< Invalid size */
#define ESP_ERR_NOT_FOUND 0x105 /*!< Requested resource not found */
#define ESP_ERR_NOT_SUPPORTED 0x106 /*!< Operation or feature not supported */
#define ESP_ERR_TIMEOUT 0x107 /*!< Operation timed out */
#define ESP_ERR_INVALID_RESPONSE 0x108 /*!< Received response was invalid */
#define ESP_ERR_INVALID_CRC 0x109 /*!< CRC or checksum was invalid */
#define ESP_ERR_INVALID_CRC 0x109 /*!< CRC or checksum was invalid */
#define ESP_ERR_INVALID_VERSION 0x10A /*!< Version was invalid */
#define ESP_ERR_INVALID_MAC 0x10B /*!< MAC address was invalid */
#define ESP_ERR_INVALID_MAC 0x10B /*!< MAC address was invalid */
#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */
#define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */
#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */
#define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */
/**
* @brief Returns string for esp_err_t error codes

File diff suppressed because it is too large Load Diff

View File

@ -33,22 +33,20 @@ extern "C" {
* Structures
*******************************************************/
typedef struct {
int scan; /**< minimum scan times before being a root, default:10. */
int vote; /**< max vote times in self-healing, default:1000. */
int fail; /**< parent selection fail times. If the scan times reach this value,
device will disconnect with associated children and join self-healing, default:120. */
int monitor_ie; /**< acceptable times of parent networking IE change before update self networking IE, default:10. */
int scan; /**< minimum scan times before being a root, default:10 */
int vote; /**< max vote times in self-healing, default:1000 */
int fail; /**< parent selection fail times, if the scan times reach this value,
device will disconnect with associated children and join self-healing. default:60 */
int monitor_ie; /**< acceptable times of parent networking IE change before update its own networking IE. default:3 */
} mesh_attempts_t;
typedef struct {
int duration_ms; /* parent weak RSSI monitor duration. If the RSSI with current parent is less than cnx_rssi continuously
within this duration_ms, device will search for a better parent. */
int duration_ms; /* parent weak RSSI monitor duration, if the RSSI continues to be weak during this duration_ms,
device will search for a new parent. */
int cnx_rssi; /* RSSI threshold for keeping a good connection with parent.
If set a value greater than -120 dBm, device will arm a timer to monitor current RSSI at a period time of
duration_ms. */
int select_rssi; /* RSSI threshold for parent selection, should be a value greater than switch_rssi. */
int switch_rssi; /* RSSI threshold for parent switch. Device will disassociate current parent and switch to a new parent when
the RSSI with the new parent is greater than this set threshold. */
If set a value greater than -120 dBm, a timer will be armed to monitor parent RSSI at a period time of duration_ms. */
int select_rssi; /* RSSI threshold for parent selection. It should be a value greater than switch_rssi. */
int switch_rssi; /* Disassociate with current parent and switch to a new parent when the RSSI is greater than this set threshold. */
int backoff_rssi; /* RSSI threshold for connecting to the root */
} mesh_switch_parent_t;
@ -59,7 +57,7 @@ typedef struct {
} mesh_rssi_threshold_t;
/**
* @brief mesh networking IE
* @brief Mesh networking IE
*/
typedef struct {
/**< mesh networking IE head */
@ -82,7 +80,7 @@ typedef struct {
uint16_t root_cap; /**< root capacity */
uint16_t self_cap; /**< self capacity */
uint16_t layer2_cap; /**< layer2 capacity */
uint16_t scan_ap_num; /**< the number of scanned APs */
uint16_t scan_ap_num; /**< the number of scanning APs */
int8_t rssi; /**< RSSI of the parent */
int8_t router_rssi; /**< RSSI of the router */
uint8_t flag; /**< flag of networking */
@ -102,9 +100,9 @@ typedef struct {
* Function Definitions
*******************************************************/
/**
* @brief set mesh softAP beacon interval
* @brief Set mesh softAP beacon interval
*
* @param interval beacon interval(ms) (100ms ~ 60000ms)
* @param[in] interval beacon interval (msecs) (100 msecs ~ 60000 msecs)
*
* @return
* - ESP_OK
@ -114,9 +112,9 @@ typedef struct {
esp_err_t esp_mesh_set_beacon_interval(int interval_ms);
/**
* @brief get mesh softAP beacon interval
* @brief Get mesh softAP beacon interval
*
* @param interval beacon interval(ms)
* @param[out] interval beacon interval (msecs)
*
* @return
* - ESP_OK
@ -124,9 +122,9 @@ esp_err_t esp_mesh_set_beacon_interval(int interval_ms);
esp_err_t esp_mesh_get_beacon_interval(int *interval_ms);
/**
* @brief set attempts for mesh self-organized networking
* @brief Set attempts for mesh self-organized networking
*
* @param attempts
* @param[in] attempts
*
* @return
* - ESP_OK
@ -135,9 +133,9 @@ esp_err_t esp_mesh_get_beacon_interval(int *interval_ms);
esp_err_t esp_mesh_set_attempts(mesh_attempts_t *attempts);
/**
* @brief get attempts for mesh self-organized networking
* @brief Get attempts for mesh self-organized networking
*
* @param attempts
* @param[out] attempts
*
* @return
* - ESP_OK
@ -146,9 +144,9 @@ esp_err_t esp_mesh_set_attempts(mesh_attempts_t *attempts);
esp_err_t esp_mesh_get_attempts(mesh_attempts_t *attempts);
/**
* @brief set parameters for parent switch
* @brief Set parameters for parent switch
*
* @param paras parameters for parent switch
* @param[in] paras parameters for parent switch
*
* @return
* - ESP_OK
@ -157,9 +155,9 @@ esp_err_t esp_mesh_get_attempts(mesh_attempts_t *attempts);
esp_err_t esp_mesh_set_switch_parent_paras(mesh_switch_parent_t *paras);
/**
* @brief get parameters for parent switch
* @brief Get parameters for parent switch
*
* @param paras parameters for parent switch
* @param[out] paras parameters for parent switch
*
* @return
* - ESP_OK
@ -168,12 +166,12 @@ esp_err_t esp_mesh_set_switch_parent_paras(mesh_switch_parent_t *paras);
esp_err_t esp_mesh_get_switch_parent_paras(mesh_switch_parent_t *paras);
/**
* @brief set RSSI threshold
* The default high RSSI threshold value is -78 dBm.
* The default medium RSSI threshold value is -82 dBm.
* The default low RSSI threshold value is -85 dBm.
* @brief Set RSSI threshold
* - The default high RSSI threshold value is -78 dBm.
* - The default medium RSSI threshold value is -82 dBm.
* - The default low RSSI threshold value is -85 dBm.
*
* @param threshold RSSI threshold
* @param[in] threshold RSSI threshold
*
* @return
* - ESP_OK
@ -182,8 +180,9 @@ esp_err_t esp_mesh_get_switch_parent_paras(mesh_switch_parent_t *paras);
esp_err_t esp_mesh_set_rssi_threshold(const mesh_rssi_threshold_t *threshold);
/**
* @brief get RSSI threshold
* @param threshold RSSI threshold
* @brief Get RSSI threshold
*
* @param[out] threshold RSSI threshold
*
* @return
* - ESP_OK
@ -192,11 +191,11 @@ esp_err_t esp_mesh_set_rssi_threshold(const mesh_rssi_threshold_t *threshold);
esp_err_t esp_mesh_get_rssi_threshold(mesh_rssi_threshold_t *threshold);
/**
* @brief enable the minimum rate to 6Mbps
* @brief Enable the minimum rate to 6 Mbps
*
* @attention This API shall be called before WiFi start.
* @attention This API shall be called before Wi-Fi is started.
*
* @param is_6m enable or not
* @param[in] is_6m enable or not
*
* @return
* - ESP_OK
@ -204,7 +203,7 @@ esp_err_t esp_mesh_get_rssi_threshold(mesh_rssi_threshold_t *threshold);
esp_err_t esp_mesh_set_6m_rate(bool is_6m);
/**
* @brief print the number of txQ waiting
* @brief Print the number of txQ waiting
*
* @return
* - ESP_OK
@ -213,7 +212,7 @@ esp_err_t esp_mesh_set_6m_rate(bool is_6m);
esp_err_t esp_mesh_print_txQ_waiting(void);
/**
* @brief print the number of rxQ waiting
* @brief Print the number of rxQ waiting
*
* @return
* - ESP_OK
@ -222,9 +221,9 @@ esp_err_t esp_mesh_print_txQ_waiting(void);
esp_err_t esp_mesh_print_rxQ_waiting(void);
/**
* @brief set passive scan time
* @brief Set passive scan time
*
* @param interval_ms passive scan time(ms)
* @param[in] interval_ms passive scan time (msecs)
*
* @return
* - ESP_OK
@ -234,19 +233,19 @@ esp_err_t esp_mesh_print_rxQ_waiting(void);
esp_err_t esp_mesh_set_passive_scan_time(int time_ms);
/**
* @brief get passive scan time
* @brief Get passive scan time
*
* @return interval_ms passive scan time(ms)
* @return interval_ms passive scan time (msecs)
*/
int esp_mesh_get_passive_scan_time(void);
/**
* @brief set announce interval
* The default short interval is 500 milliseconds.
* The default long interval is 3000 milliseconds.
* @brief Set announce interval
* - The default short interval is 500 milliseconds.
* - The default long interval is 3000 milliseconds.
*
* @param short_ms shall be greater than the default value
* @param long_ms shall be greater than the default value
* @param[in] short_ms shall be greater than the default value
* @param[in] long_ms shall be greater than the default value
*
* @return
* - ESP_OK
@ -254,10 +253,10 @@ int esp_mesh_get_passive_scan_time(void);
esp_err_t esp_mesh_set_announce_interval(int short_ms, int long_ms);
/**
* @brief get announce interval
* @brief Get announce interval
*
* @param short_ms short interval
* @param long_ms long interval
* @param[out] short_ms short interval
* @param[out] long_ms long interval
*
* @return
* - ESP_OK

View File

@ -151,18 +151,31 @@ uint32_t esp_get_minimum_free_heap_size( void );
/**
* @brief Get one random 32-bit word from hardware RNG
*
* The hardware RNG is fully functional whenever an RF subsystem is running (ie Bluetooth or WiFi is enabled). For secure
* The hardware RNG is fully functional whenever an RF subsystem is running (ie Bluetooth or WiFi is enabled). For
* random values, call this function after WiFi or Bluetooth are started.
*
* When the app is running without an RF subsystem enabled, it should be considered a PRNG. To help improve this
* situation, the RNG is pre-seeded with entropy while the IDF bootloader is running. However no new entropy is
* available during the window of time between when the bootloader exits and an RF subsystem starts. It may be possible
* to discern a non-random pattern in a very large amount of output captured during this window of time.
* If the RF subsystem is not used by the program, the function bootloader_random_enable() can be called to enable an
* entropy source. bootloader_random_disable() must be called before RF subsystem or I2S peripheral are used. See these functions'
* documentation for more details.
*
* Any time the app is running without an RF subsystem (or bootloader_random) enabled, RNG hardware should be
* considered a PRNG. A very small amount of entropy is available due to pre-seeding while the IDF
* bootloader is running, but this should not be relied upon for any use.
*
* @return Random value between 0 and UINT32_MAX
*/
uint32_t esp_random(void);
/**
* @brief Fill a buffer with random bytes from hardware RNG
*
* @note This function has the same restrictions regarding available entropy as esp_random()
*
* @param buf Pointer to buffer to fill with random numbers.
* @param len Length of buffer in bytes
*/
void esp_fill_random(void *buf, size_t len);
/**
* @brief Set base MAC address with the MAC address which is stored in BLK3 of EFUSE or
* external storage e.g. flash and EEPROM.

View File

@ -223,7 +223,9 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config);
*
* @attention 1. This API should be called if you want to remove WiFi driver from the system
*
* @return ESP_OK: succeed
* @return
* - ESP_OK: succeed
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
*/
esp_err_t esp_wifi_deinit(void);

View File

@ -272,6 +272,9 @@ PROVIDE ( r_E1 = 0x400108e8 );
PROVIDE ( r_E21 = 0x40010968 );
PROVIDE ( r_E22 = 0x400109b4 );
PROVIDE ( r_E3 = 0x40010a58 );
PROVIDE ( lm_n192_mod_mul = 0x40011dc0 );
PROVIDE ( lm_n192_mod_add = 0x40011e9c );
PROVIDE ( lm_n192_mod_sub = 0x40011eec );
PROVIDE ( r_ea_alarm_clear = 0x40015ab4 );
PROVIDE ( r_ea_alarm_set = 0x40015a10 );
PROVIDE ( _read_r = 0x4000bda8 );
@ -301,6 +304,7 @@ PROVIDE ( r_ecc_gen_new_public_key = 0x400170c0 );
PROVIDE ( r_ecc_gen_new_secret_key = 0x400170e4 );
PROVIDE ( r_ecc_get_debug_Keys = 0x40017224 );
PROVIDE ( r_ecc_init = 0x40016dbc );
PROVIDE ( ecc_point_multiplication_uint8_256 = 0x40016804);
PROVIDE ( RecvBuff = 0x3ffe009c );
PROVIDE ( r_em_buf_init = 0x4001729c );
PROVIDE ( r_em_buf_rx_buff_addr_get = 0x400173e8 );
@ -599,6 +603,14 @@ PROVIDE ( r_lc_util_get_offset_clke = 0x4002f538 );
PROVIDE ( r_lc_util_get_offset_clkn = 0x4002f51c );
PROVIDE ( r_lc_util_set_loc_trans_coll = 0x4002f500 );
PROVIDE ( r_lc_version = 0x40020a30 );
PROVIDE ( lc_set_encap_pdu_data_p192 = 0x4002e4c8 );
PROVIDE ( lc_set_encap_pdu_data_p256 = 0x4002e454 );
PROVIDE ( lm_get_auth_method = 0x40023420);
PROVIDE ( lmp_accepted_ext_handler = 0x40027290 );
PROVIDE ( lmp_not_accepted_ext_handler = 0x40029c54 );
PROVIDE ( lmp_clk_adj_handler = 0x40027468 );
PROVIDE ( lmp_clk_adj_ack_handler = 0x400274f4 );
PROVIDE ( lm_get_auth_method = 0x40023420);
PROVIDE ( lmp_accepted_ext_handler = 0x40027290 );
PROVIDE ( lmp_not_accepted_ext_handler = 0x40029c54 );
PROVIDE ( lmp_clk_adj_handler = 0x40027468 );

@ -1 +1 @@
Subproject commit 4c69c1ad8da7a9cbe8e27598b8c91780ac0b5068
Subproject commit ea4bb37b0f3df868608295cf6a5c08a0585a3881

View File

@ -531,6 +531,18 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle,
return err;
}
#if CONFIG_REDUCE_PHY_TX_POWER
static void esp_phy_reduce_tx_power(esp_phy_init_data_t* init_data)
{
uint8_t i;
for(i = 0; i < PHY_TX_POWER_NUM; i++) {
// LOWEST_PHY_TX_POWER is the lowest tx power
init_data->params[PHY_TX_POWER_OFFSET+i] = PHY_TX_POWER_LOWEST;
}
}
#endif
void esp_phy_load_cal_and_init(phy_rf_module_t module)
{
esp_phy_calibration_data_t* cal_data =
@ -540,11 +552,30 @@ void esp_phy_load_cal_and_init(phy_rf_module_t module)
abort();
}
#if CONFIG_REDUCE_PHY_TX_POWER
const esp_phy_init_data_t* phy_init_data = esp_phy_get_init_data();
if (phy_init_data == NULL) {
ESP_LOGE(TAG, "failed to obtain PHY init data");
abort();
}
esp_phy_init_data_t* init_data = (esp_phy_init_data_t*) malloc(sizeof(esp_phy_init_data_t));
if (init_data == NULL) {
ESP_LOGE(TAG, "failed to allocate memory for phy init data");
abort();
}
memcpy(init_data, phy_init_data, sizeof(esp_phy_init_data_t));
if (esp_reset_reason() == ESP_RST_BROWNOUT) {
esp_phy_reduce_tx_power(init_data);
}
#else
const esp_phy_init_data_t* init_data = esp_phy_get_init_data();
if (init_data == NULL) {
ESP_LOGE(TAG, "failed to obtain PHY init data");
abort();
}
#endif
#ifdef CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE
esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL;
@ -571,7 +602,12 @@ void esp_phy_load_cal_and_init(phy_rf_module_t module)
esp_phy_rf_init(init_data, PHY_RF_CAL_FULL, cal_data, module);
#endif
#if CONFIG_REDUCE_PHY_TX_POWER
esp_phy_release_init_data(phy_init_data);
free(init_data);
#else
esp_phy_release_init_data(init_data);
#endif
free(cal_data); // PHY maintains a copy of calibration data, so we can free this
}

View File

@ -22,6 +22,11 @@
#define PHY_INIT_MAGIC "PHYINIT"
// define the lowest tx power as LOWEST_PHY_TX_POWER
#define PHY_TX_POWER_LOWEST LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 52)
#define PHY_TX_POWER_OFFSET 44
#define PHY_TX_POWER_NUM 5
static const char phy_init_magic_pre[] = PHY_INIT_MAGIC;
/**

View File

@ -185,7 +185,7 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size) {
return ESP_ERR_NO_MEM;
}
uint32_t caps[] = { MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT };
uint32_t caps[] = { 0, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT };
esp_err_t e = heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+next_size-1);
if (e != ESP_OK) {
return e;

View File

@ -6,6 +6,7 @@
#include "esp_system.h"
#include "esp_event_loop.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "esp_log.h"
#include "nvs_flash.h"
@ -42,6 +43,11 @@ static esp_err_t event_handler(void *ctx, system_event_t *event)
static void test_wifi_init_deinit(wifi_init_config_t *cfg, wifi_config_t* wifi_config)
{
ESP_LOGI(TAG, EMPH_STR("esp_wifi_deinit"));
TEST_ESP_ERR(ESP_ERR_WIFI_NOT_INIT, esp_wifi_deinit());
ESP_LOGI(TAG, EMPH_STR("esp_wifi_get_mode"));
wifi_mode_t mode_get;
TEST_ESP_ERR(ESP_ERR_WIFI_NOT_INIT, esp_wifi_get_mode(&mode_get));
ESP_LOGI(TAG, EMPH_STR("esp_wifi_init"));
TEST_ESP_OK(esp_wifi_init(cfg));
ESP_LOGI(TAG, EMPH_STR("esp_wifi_set_mode"));
@ -54,6 +60,8 @@ static void test_wifi_init_deinit(wifi_init_config_t *cfg, wifi_config_t* wifi_c
static void test_wifi_start_stop(wifi_init_config_t *cfg, wifi_config_t* wifi_config)
{
ESP_LOGI(TAG, EMPH_STR("esp_wifi_stop"));
TEST_ESP_ERR(ESP_ERR_WIFI_NOT_INIT, esp_wifi_stop());
ESP_LOGI(TAG, EMPH_STR("esp_wifi_init"));
TEST_ESP_OK(esp_wifi_init(cfg));
ESP_LOGI(TAG, EMPH_STR("esp_wifi_set_mode"));

View File

@ -0,0 +1,67 @@
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "esp_system.h"
/* Note: these are just sanity tests, not the same as
entropy tests
*/
TEST_CASE("call esp_random()", "[random]")
{
const size_t NUM_RANDOM = 128; /* in most cases this is massive overkill */
uint32_t zeroes = UINT32_MAX;
uint32_t ones = 0;
for (int i = 0; i < NUM_RANDOM - 1; i++) {
uint32_t r = esp_random();
ones |= r;
zeroes &= ~r;
}
/* assuming a 'white' random distribution, we can expect
usually at least one time each bit will be zero and at
least one time each will be one. Statistically this
can still fail, just *very* unlikely to. */
TEST_ASSERT_EQUAL_HEX32(0, zeroes);
TEST_ASSERT_EQUAL_HEX32(UINT32_MAX, ones);
}
TEST_CASE("call esp_fill_random()", "[random]")
{
const size_t NUM_BUF = 200;
const size_t BUF_SZ = 16;
uint8_t buf[NUM_BUF][BUF_SZ];
uint8_t zero_buf[BUF_SZ];
uint8_t one_buf[BUF_SZ];
bzero(buf, sizeof(buf));
bzero(one_buf, sizeof(zero_buf));
memset(zero_buf, 0xFF, sizeof(one_buf));
for (int i = 0; i < NUM_BUF; i++) {
esp_fill_random(buf[i], BUF_SZ);
}
/* No two 128-bit buffers should be the same
(again, statistically this could happen but it's very unlikely) */
for (int i = 0; i < NUM_BUF; i++) {
for (int j = 0; j < NUM_BUF; j++) {
if (i != j) {
TEST_ASSERT_NOT_EQUAL(0, memcmp(buf[i], buf[j], BUF_SZ));
}
}
}
/* Do the same all bits are zero and one at least once test across the buffers */
for (int i = 0; i < NUM_BUF; i++) {
for (int x = 0; x < BUF_SZ; x++) {
zero_buf[x] &= ~buf[i][x];
one_buf[x] |= buf[i][x];
}
}
for (int x = 0; x < BUF_SZ; x++) {
TEST_ASSERT_EQUAL_HEX8(0, zero_buf[x]);
TEST_ASSERT_EQUAL_HEX8(0xFF, one_buf[x]);
}
}

View File

@ -58,14 +58,14 @@ APP_BIN_UNSIGNED ?= $(APP_BIN)
$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) | check_python_dependencies
$(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info check_python_dependencies
flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(APP_OFFSET))..."
ifdef CONFIG_SECURE_BOOT_ENABLED
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
endif
$(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info check_python_dependencies
app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies
@echo "Flashing app to serial port $(ESPPORT), offset $(APP_OFFSET)..."
$(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN)
@ -73,7 +73,7 @@ app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) pa
# at the project level as long as qualified path
COMPONENT_SUBMODULES += $(COMPONENT_PATH)/esptool
erase_flash: check_python_dependencies
erase_flash: | check_python_dependencies
@echo "Erasing entire flash..."
$(ESPTOOLPY_SERIAL) erase_flash
@ -90,14 +90,14 @@ endif
# note: if you want to run miniterm from command line, can simply run
# miniterm.py on the console. The '$(PYTHON) -m serial.tools.miniterm'
# is to allow for the $(PYTHON) variable overriding the python path.
simple_monitor: check_python_dependencies $(call prereq_if_explicit,%flash)
simple_monitor: $(call prereq_if_explicit,%flash) | check_python_dependencies
$(MONITOR_PYTHON) -m serial.tools.miniterm --rts 0 --dtr 0 --raw $(ESPPORT) $(MONITORBAUD)
PRINT_FILTER ?=
MONITOR_OPTS := --baud $(MONITORBAUD) --port $(ESPPORT) --toolchain-prefix $(CONFIG_TOOLPREFIX) --make "$(MAKE)" --print_filter "$(PRINT_FILTER)"
monitor: check_python_dependencies $(call prereq_if_explicit,%flash)
monitor: $(call prereq_if_explicit,%flash) | check_python_dependencies
$(summary) MONITOR
[ -f $(APP_ELF) ] || echo "*** 'make monitor' target requires an app to be compiled and flashed first."
[ -f $(APP_ELF) ] || echo "*** Run 'make flash monitor' to build, flash and monitor"

View File

@ -167,9 +167,7 @@ TEST_CASE("(SD) write/read speed test", "[fatfs][sd][test_env=UT_T1_SDMODE][time
const size_t buf_size = 16 * 1024;
uint32_t* buf = (uint32_t*) calloc(1, buf_size);
for (size_t i = 0; i < buf_size / 4; ++i) {
buf[i] = esp_random();
}
esp_fill_random(buf, buf_size);
const size_t file_size = 1 * 1024 * 1024;
speed_test(buf, 4 * 1024, file_size, true);

View File

@ -162,9 +162,7 @@ TEST_CASE("(WL) write/read speed test", "[fatfs][wear_levelling][timeout=60]")
const size_t buf_size = 16 * 1024;
uint32_t* buf = (uint32_t*) calloc(1, buf_size);
for (size_t i = 0; i < buf_size / 4; ++i) {
buf[i] = esp_random();
}
esp_fill_random(buf, buf_size);
const size_t file_size = 256 * 1024;
const char* file = "/spiflash/256k.bin";

View File

@ -2040,16 +2040,19 @@ BaseType_t i;
/* Add the per-core idle tasks at the lowest priority. */
for ( i=0; i<portNUM_PROCESSORS; i++) {
//Generate idle task name
char cIdleName[configMAX_TASK_NAME_LEN];
snprintf(cIdleName, configMAX_TASK_NAME_LEN, "IDLE%d", i);
#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
{
/* Create the idle task, storing its handle in xIdleTaskHandle so it can
be returned by the xTaskGetIdleTaskHandle() function. */
xReturn = xTaskCreatePinnedToCore( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle[i], i ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
xReturn = xTaskCreatePinnedToCore( prvIdleTask, cIdleName, tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle[i], i ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
}
#else
{
/* Create the idle task without storing its handle. */
xReturn = xTaskCreatePinnedToCore( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL, i); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
xReturn = xTaskCreatePinnedToCore( prvIdleTask, cIdleName, tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL, i); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
}
#endif /* INCLUDE_xTaskGetIdleTaskHandle */
}

View File

@ -206,7 +206,7 @@ esp_err_t heap_caps_add_region_with_caps(const uint32_t caps[], intptr_t start,
}
}
heap_t *p_new = malloc(sizeof(heap_t));
heap_t *p_new = heap_caps_malloc(sizeof(heap_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (p_new == NULL) {
err = ESP_ERR_NO_MEM;
goto done;
@ -218,7 +218,7 @@ esp_err_t heap_caps_add_region_with_caps(const uint32_t caps[], intptr_t start,
p_new->heap = multi_heap_register((void *)start, end - start);
SLIST_NEXT(p_new, next) = NULL;
if (p_new->heap == NULL) {
err = ESP_FAIL;
err = ESP_ERR_INVALID_SIZE;
goto done;
}
multi_heap_set_lock(p_new->heap, &p_new->heap_mux);

View File

@ -81,6 +81,7 @@ esp_err_t heap_caps_add_region(intptr_t start, intptr_t end);
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if a parameter is invalid
* - ESP_ERR_NO_MEM if no memory to register new heap.
* - ESP_ERR_INVALID_SIZE if the memory region is too small to fit a heap
* - ESP_FAIL if region overlaps the start and/or end of an existing region
*/
esp_err_t heap_caps_add_region_with_caps(const uint32_t caps[], intptr_t start, intptr_t end);

View File

@ -147,6 +147,12 @@ static bool verify_fill_pattern(void *data, size_t size, bool print_errors, bool
MULTI_HEAP_STDERR_PRINTF("CORRUPT HEAP: Invalid data at %p. Expected 0x%08x got 0x%08x\n", p, EXPECT_WORD, *p);
}
valid = false;
#ifndef NDEBUG
/* If an assertion is going to fail as soon as we're done verifying the pattern, leave the rest of the
buffer contents as-is for better post-mortem analysis
*/
swap_pattern = false;
#endif
}
if (swap_pattern) {
*p = REPLACE_WORD;
@ -164,6 +170,9 @@ static bool verify_fill_pattern(void *data, size_t size, bool print_errors, bool
MULTI_HEAP_STDERR_PRINTF("CORRUPT HEAP: Invalid data at %p. Expected 0x%02x got 0x%02x\n", p, (uint8_t)EXPECT_WORD, *p);
}
valid = false;
#ifndef NDEBUG
swap_pattern = false; // same as above
#endif
}
if (swap_pattern) {
p[i] = (uint8_t)REPLACE_WORD;

View File

@ -14,14 +14,6 @@
#include "randombytes_default.h"
#include "esp_system.h"
static void randombytes_esp32_random_buf(void * const buf, const size_t size)
{
uint8_t *p = (uint8_t *)buf;
for (size_t i = 0; i < size; i++) {
p[i] = esp_random();
}
}
static const char *randombytes_esp32_implementation_name(void)
{
return "esp32";
@ -39,7 +31,7 @@ const struct randombytes_implementation randombytes_esp32_implementation = {
.random = esp_random,
.stir = NULL,
.uniform = NULL,
.buf = randombytes_esp32_random_buf,
.buf = esp_fill_random,
.close = NULL,
};

View File

@ -7,17 +7,18 @@
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <esp_system.h>
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
#ifndef MBEDTLS_ENTROPY_HARDWARE_ALT
#error "MBEDTLS_ENTROPY_HARDWARE_ALT should always be set in ESP-IDF"
#endif
extern int os_get_random(unsigned char *buf, size_t len);
int mbedtls_hardware_poll( void *data,
unsigned char *output, size_t len, size_t *olen )
{
os_get_random(output, len);
esp_fill_random(output, len);
*olen = len;
return 0;
}
#endif

View File

@ -0,0 +1,296 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This header file is based on the termios header of
// "The Single UNIX (r) Specification, Version 2, Copyright (c) 1997 The Open Group".
#ifndef __ESP_SYS_TERMIOS_H__
#define __ESP_SYS_TERMIOS_H__
// ESP-IDF NOTE: This header provides only a compatibility layer for macros and functions defined in sys/termios.h.
// Not everything has a defined meaning for ESP-IDF (e.g. process leader IDs) and therefore are likely to be stubbed
// in actual implementations.
#include <stdint.h>
#include <sys/types.h>
#include "sdkconfig.h"
#ifdef CONFIG_SUPPORT_TERMIOS
// subscripts for the array c_cc:
#define VEOF 0 /** EOF character */
#define VEOL 1 /** EOL character */
#define VERASE 2 /** ERASE character */
#define VINTR 3 /** INTR character */
#define VKILL 4 /** KILL character */
#define VMIN 5 /** MIN value */
#define VQUIT 6 /** QUIT character */
#define VSTART 7 /** START character */
#define VSTOP 8 /** STOP character */
#define VSUSP 9 /** SUSP character */
#define VTIME 10 /** TIME value */
#define NCCS (VTIME + 1) /** Size of the array c_cc for control characters */
// input modes for use as flags in the c_iflag field
#define BRKINT (1u << 0) /** Signal interrupt on break. */
#define ICRNL (1u << 1) /** Map CR to NL on input. */
#define IGNBRK (1u << 2) /** Ignore break condition. */
#define IGNCR (1u << 3) /** Ignore CR. */
#define IGNPAR (1u << 4) /** Ignore characters with parity errors. */
#define INLCR (1u << 5) /** Map NL to CR on input. */
#define INPCK (1u << 6) /** Enable input parity check. */
#define ISTRIP (1u << 7) /** Strip character. */
#define IUCLC (1u << 8) /** Map upper-case to lower-case on input (LEGACY). */
#define IXANY (1u << 9) /** Enable any character to restart output. */
#define IXOFF (1u << 10) /** Enable start/stop input control. */
#define IXON (1u << 11) /** Enable start/stop output control. */
#define PARMRK (1u << 12) /** Mark parity errors. */
// output Modes for use as flags in the c_oflag field
#define OPOST (1u << 0) /** Post-process output */
#define OLCUC (1u << 1) /** Map lower-case to upper-case on output (LEGACY). */
#define ONLCR (1u << 2) /** Map NL to CR-NL on output. */
#define OCRNL (1u << 3) /** Map CR to NL on output. */
#define ONOCR (1u << 4) /** No CR output at column 0. */
#define ONLRET (1u << 5) /** NL performs CR function. */
#define OFILL (1u << 6) /** Use fill characters for delay. */
#define NLDLY (1u << 7) /** Select newline delays: */
#define NL0 (0u << 7) /** Newline character type 0. */
#define NL1 (1u << 7) /** Newline character type 1. */
#define CRDLY (3u << 8) /** Select carriage-return delays: */
#define CR0 (0u << 8) /** Carriage-return delay type 0. */
#define CR1 (1u << 8) /** Carriage-return delay type 1. */
#define CR2 (2u << 8) /** Carriage-return delay type 2. */
#define CR3 (3u << 8) /** Carriage-return delay type 3. */
#define TABDLY (3u << 10) /** Select horizontal-tab delays: */
#define TAB0 (0u << 10) /** Horizontal-tab delay type 0. */
#define TAB1 (1u << 10) /** Horizontal-tab delay type 1. */
#define TAB2 (2u << 10) /** Horizontal-tab delay type 2. */
#define TAB3 (3u << 10) /** Expand tabs to spaces. */
#define BSDLY (1u << 12) /** Select backspace delays: */
#define BS0 (0u << 12) /** Backspace-delay type 0. */
#define BS1 (1u << 12) /** Backspace-delay type 1. */
#define VTDLY (1u << 13) /** Select vertical-tab delays: */
#define VT0 (0u << 13) /** Vertical-tab delay type 0. */
#define VT1 (1u << 13) /** Vertical-tab delay type 1. */
#define FFDLY (1u << 14) /** Select form-feed delays: */
#define FF0 (0u << 14) /** Form-feed delay type 0. */
#define FF1 (1u << 14) /** Form-feed delay type 1. */
// Baud Rate Selection. Valid values for objects of type speed_t:
// CBAUD range B0 - B38400
#define B0 0 /** Hang up */
#define B50 1
#define B75 2
#define B110 3
#define B134 4
#define B150 5
#define B200 6
#define B300 7
#define B600 8
#define B1200 9
#define B1800 10
#define B2400 11
#define B4800 12
#define B9600 13
#define B19200 14
#define B38400 15
// CBAUDEX range B57600 - B4000000
#define B57600 16
#define B115200 17
#define B230400 18
#define B460800 19
#define B500000 20
#define B576000 21
#define B921600 22
#define B1000000 23
#define B1152000 24
#define B1500000 25
#define B2000000 26
#define B2500000 27
#define B3000000 28
#define B3500000 29
#define B4000000 30
// Control Modes for the c_cflag field:
#define CSIZE (3u << 0) /* Character size: */
#define CS5 (0u << 0) /** 5 bits. */
#define CS6 (1u << 0) /** 6 bits. */
#define CS7 (2u << 0) /** 7 bits. */
#define CS8 (3u << 0) /** 8 bits. */
#define CSTOPB (1u << 2) /** Send two stop bits, else one. */
#define CREAD (1u << 3) /** Enable receiver. */
#define PARENB (1u << 4) /** Parity enable. */
#define PARODD (1u << 5) /** Odd parity, else even. */
#define HUPCL (1u << 6) /** Hang up on last close. */
#define CLOCAL (1u << 7) /** Ignore modem status lines. */
#define CBAUD (1u << 8) /** Use baud rates defined by B0-B38400 macros. */
#define CBAUDEX (1u << 9) /** Use baud rates defined by B57600-B4000000 macros. */
#define BOTHER (1u << 10) /** Use custom baud rates */
// Local Modes for c_lflag field:
#define ECHO (1u << 0) /** Enable echo. */
#define ECHOE (1u << 1) /** Echo erase character as error-correcting backspace. */
#define ECHOK (1u << 2) /** Echo KILL. */
#define ECHONL (1u << 3) /** Echo NL. */
#define ICANON (1u << 4) /** Canonical input (erase and kill processing). */
#define IEXTEN (1u << 5) /** Enable extended input character processing. */
#define ISIG (1u << 6) /** Enable signals. */
#define NOFLSH (1u << 7) /** Disable flush after interrupt or quit. */
#define TOSTOP (1u << 8) /** Send SIGTTOU for background output. */
#define XCASE (1u << 9) /** Canonical upper/lower presentation (LEGACY). */
// Attribute Selection constants for use with tcsetattr():
#define TCSANOW 0 /** Change attributes immediately. */
#define TCSADRAIN 1 /** Change attributes when output has drained. */
#define TCSAFLUSH 2 /** Change attributes when output has drained; also flush pending input. */
// Line Control constants for use with tcflush():
#define TCIFLUSH 0 /** Flush pending input. Flush untransmitted output. */
#define TCIOFLUSH 1 /** Flush both pending input and untransmitted output. */
#define TCOFLUSH 2 /** Flush untransmitted output. */
// constants for use with tcflow():
#define TCIOFF 0 /** Transmit a STOP character, intended to suspend input data. */
#define TCION 1 /** Transmit a START character, intended to restart input data. */
#define TCOOFF 2 /** Suspend output. */
#define TCOON 3 /** Restart output. */
typedef uint8_t cc_t;
typedef uint32_t speed_t;
typedef uint16_t tcflag_t;
struct termios
{
tcflag_t c_iflag; /** Input modes */
tcflag_t c_oflag; /** Output modes */
tcflag_t c_cflag; /** Control modes */
tcflag_t c_lflag; /** Local modes */
cc_t c_cc[NCCS]; /** Control characters */
speed_t c_ispeed; /** input baud rate */
speed_t c_ospeed; /** output baud rate */
};
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Extracts the input baud rate from the input structure exactly (without interpretation).
*
* @param p input termios structure
* @return input baud rate
*/
speed_t cfgetispeed(const struct termios *p);
/**
* @brief Extracts the output baud rate from the input structure exactly (without interpretation).
*
* @param p input termios structure
* @return output baud rate
*/
speed_t cfgetospeed(const struct termios *p);
/**
* @brief Set input baud rate in the termios structure
*
* There is no effect in hardware until a subsequent call of tcsetattr().
*
* @param p input termios structure
* @param sp input baud rate
* @return 0 when successful, -1 otherwise with errno set
*/
int cfsetispeed(struct termios *p, speed_t sp);
/**
* @brief Set output baud rate in the termios structure
*
* There is no effect in hardware until a subsequent call of tcsetattr().
*
* @param p input termios structure
* @param sp output baud rate
* @return 0 when successful, -1 otherwise with errno set
*/
int cfsetospeed(struct termios *p, speed_t sp);
/**
* @brief Wait for transmission of output
*
* @param fd file descriptor of the terminal
* @return 0 when successful, -1 otherwise with errno set
*/
int tcdrain(int fd);
/**
* @brief Suspend or restart the transmission or reception of data
*
* @param fd file descriptor of the terminal
* @param action selects actions to do
* @return 0 when successful, -1 otherwise with errno set
*/
int tcflow(int fd, int action);
/**
* @brief Flush non-transmitted output data and non-read input data
*
* @param fd file descriptor of the terminal
* @param select selects what should be flushed
* @return 0 when successful, -1 otherwise with errno set
*/
int tcflush(int fd, int select);
/**
* @brief Gets the parameters of the terminal
*
* @param fd file descriptor of the terminal
* @param p output termios structure
* @return 0 when successful, -1 otherwise with errno set
*/
int tcgetattr(int fd, struct termios *p);
/**
* @brief Get process group ID for session leader for controlling terminal
*
* @param fd file descriptor of the terminal
* @return process group ID when successful, -1 otherwise with errno set
*/
pid_t tcgetsid(int fd);
/**
* @brief Send a break for a specific duration
*
* @param fd file descriptor of the terminal
* @param duration duration of break
* @return 0 when successful, -1 otherwise with errno set
*/
int tcsendbreak(int fd, int duration);
/**
* @brief Sets the parameters of the terminal
*
* @param fd file descriptor of the terminal
* @param optional_actions optional actions
* @param p input termios structure
* @return 0 when successful, -1 otherwise with errno set
*/
int tcsetattr(int fd, int optional_actions, const struct termios *p);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // CONFIG_SUPPORT_TERMIOS
#endif //__ESP_SYS_TERMIOS_H__

View File

@ -36,17 +36,8 @@ ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)
return -1;
}
uint8_t *dst = (uint8_t *) buf;
ssize_t ret = 0;
esp_fill_random(buf, buflen);
while (ret < buflen) {
const uint32_t random = esp_random();
const int needed = buflen - ret;
const int copy_len = MIN(sizeof(random), needed);
memcpy(dst + ret, &random, copy_len);
ret += copy_len;
}
ESP_LOGD(TAG, "getrandom returns %d", ret);
return ret;
ESP_LOGD(TAG, "getrandom returns %d", buflen);
return buflen;
}

View File

@ -0,0 +1,54 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#ifdef CONFIG_SUPPORT_TERMIOS
#include <sys/termios.h>
#include <sys/errno.h>
speed_t cfgetispeed(const struct termios *p)
{
return p ? p->c_ispeed : B0;
}
speed_t cfgetospeed(const struct termios *p)
{
return p ? p->c_ospeed : B0;
}
int cfsetispeed(struct termios *p, speed_t sp)
{
if (p) {
p->c_ispeed = sp;
return 0;
} else {
errno = EINVAL;
return -1;
}
}
int cfsetospeed(struct termios *p, speed_t sp)
{
if (p) {
p->c_ospeed = sp;
return 0;
} else {
errno = EINVAL;
return -1;
}
}
#endif // CONFIG_SUPPORT_TERMIOS

View File

@ -76,7 +76,7 @@ export OTA_DATA_SIZE
PARTITION_TABLE_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN)
ESPTOOL_ALL_FLASH_ARGS += $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN)
partition_table: $(PARTITION_TABLE_BIN) partition_table_get_info check_python_dependencies
partition_table: $(PARTITION_TABLE_BIN) partition_table_get_info | check_python_dependencies
@echo "Partition table binary generated. Contents:"
@echo $(SEPARATOR)
$(GEN_ESP32PART) $<
@ -84,7 +84,7 @@ partition_table: $(PARTITION_TABLE_BIN) partition_table_get_info check_python_de
@echo "Partition flashing command:"
@echo "$(PARTITION_TABLE_FLASH_CMD)"
partition_table-flash: $(PARTITION_TABLE_BIN) check_python_dependencies
partition_table-flash: $(PARTITION_TABLE_BIN) | check_python_dependencies
@echo "Flashing partition table..."
$(PARTITION_TABLE_FLASH_CMD)

View File

@ -87,6 +87,27 @@ esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms)
return ESP_OK;
}
esp_err_t rtc_wdt_get_timeout(rtc_wdt_stage_t stage, unsigned int* timeout_ms)
{
if (stage > 3) {
return ESP_ERR_INVALID_ARG;
}
uint32_t time_tick;
if (stage == RTC_WDT_STAGE0) {
time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG1_REG);
} else if (stage == RTC_WDT_STAGE1) {
time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG2_REG);
} else if (stage == RTC_WDT_STAGE2) {
time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG3_REG);
} else {
time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG4_REG);
}
*timeout_ms = time_tick * 1000 / rtc_clk_slow_freq_get_hz();
return ESP_OK;
}
esp_err_t rtc_wdt_set_stage(rtc_wdt_stage_t stage, rtc_wdt_stage_action_t stage_sel)
{
if (stage > 3 || stage_sel > 4) {

View File

@ -142,6 +142,18 @@ void rtc_wdt_feed();
*/
esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms);
/**
* @brief Get the timeout set for the required stage.
*
* @param[in] stage Stage of rtc_wdt.
* @param[out] timeout_ms Timeout set for this stage. (not elapsed time).
*
* @return
* - ESP_OK In case of success
* - ESP_ERR_INVALID_ARG If stage has invalid value
*/
esp_err_t rtc_wdt_get_timeout(rtc_wdt_stage_t stage, unsigned int* timeout_ms);
/**
* @brief Set an action for required stage.
*

View File

@ -218,7 +218,7 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size)
if (rc == ESP_ROM_SPIFLASH_RESULT_OK) {
for (size_t sector = start; sector != end && rc == ESP_ROM_SPIFLASH_RESULT_OK; ) {
spi_flash_guard_start();
if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) {
if (sector % sectors_per_block == 0 && end - sector >= sectors_per_block) {
rc = esp_rom_spiflash_erase_block(sector / sectors_per_block);
sector += sectors_per_block;
COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE);

View File

@ -9,4 +9,10 @@ config SUPPRESS_SELECT_DEBUG_OUTPUT
It is possible to suppress these debug outputs by enabling this
option.
config SUPPORT_TERMIOS
bool "Add support for termios.h"
default y
help
Disabling this option can save memory when the support for termios.h is not required.
endmenu

View File

@ -26,8 +26,10 @@
#include <sys/reent.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/termios.h>
#include <dirent.h>
#include <string.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
@ -178,6 +180,37 @@ typedef struct
int (*truncate_p)(void* ctx, const char *path, off_t length);
int (*truncate)(const char *path, off_t length);
};
#ifdef CONFIG_SUPPORT_TERMIOS
union {
int (*tcsetattr_p)(void *ctx, int fd, int optional_actions, const struct termios *p);
int (*tcsetattr)(int fd, int optional_actions, const struct termios *p);
};
union {
int (*tcgetattr_p)(void *ctx, int fd, struct termios *p);
int (*tcgetattr)(int fd, struct termios *p);
};
union {
int (*tcdrain_p)(void *ctx, int fd);
int (*tcdrain)(int fd);
};
union {
int (*tcflush_p)(void *ctx, int fd, int select);
int (*tcflush)(int fd, int select);
};
union {
int (*tcflow_p)(void *ctx, int fd, int action);
int (*tcflow)(int fd, int action);
};
union {
pid_t (*tcgetsid_p)(void *ctx, int fd);
pid_t (*tcgetsid)(int fd);
};
union {
int (*tcsendbreak_p)(void *ctx, int fd, int duration);
int (*tcsendbreak)(int fd, int duration);
};
#endif // CONFIG_SUPPORT_TERMIOS
/** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */
esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, SemaphoreHandle_t *signal_sem);
/** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */

View File

@ -15,6 +15,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/termios.h>
#include <sys/errno.h>
#include "unity.h"
#include "rom/uart.h"
#include "soc/uart_struct.h"
@ -23,6 +26,7 @@
#include "freertos/semphr.h"
#include "driver/uart.h"
#include "esp_vfs_dev.h"
#include "esp_vfs.h"
#include "sdkconfig.h"
static void fwrite_str_loopback(const char* str, size_t size)
@ -198,3 +202,131 @@ TEST_CASE("can write to UART while another task is reading", "[vfs]")
vSemaphoreDelete(read_arg.done);
vSemaphoreDelete(write_arg.done);
}
#ifdef CONFIG_SUPPORT_TERMIOS
TEST_CASE("Can use termios for UART", "[vfs]")
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
uart_param_config(UART_NUM_1, &uart_config);
uart_driver_install(UART_NUM_1, 256, 256, 0, NULL, 0);
const int uart_fd = open("/dev/uart/1", O_RDWR);
TEST_ASSERT_NOT_EQUAL_MESSAGE(uart_fd, -1, "Cannot open UART");
esp_vfs_dev_uart_use_driver(1);
TEST_ASSERT_EQUAL(-1, tcgetattr(uart_fd, NULL));
TEST_ASSERT_EQUAL(EINVAL, errno);
struct termios tios, tios_result;
TEST_ASSERT_EQUAL(-1, tcgetattr(-1, &tios));
TEST_ASSERT_EQUAL(EBADF, errno);
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios));
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSADRAIN, &tios));
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSAFLUSH, &tios));
tios.c_iflag |= IGNCR;
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
tios.c_iflag &= (~IGNCR);
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
TEST_ASSERT_EQUAL(IGNCR, tios_result.c_iflag & IGNCR);
memset(&tios_result, 0xFF, sizeof(struct termios));
tios.c_iflag |= ICRNL;
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
tios.c_iflag &= (~ICRNL);
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
TEST_ASSERT_EQUAL(ICRNL, tios_result.c_iflag & ICRNL);
memset(&tios_result, 0xFF, sizeof(struct termios));
{
uart_word_length_t data_bit;
uart_stop_bits_t stop_bits;
uart_parity_t parity_mode;
tios.c_cflag &= (~CSIZE);
tios.c_cflag &= (~CSTOPB);
tios.c_cflag &= (~PARENB);
tios.c_cflag |= CS6;
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
tios.c_cflag &= (~CSIZE);
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
TEST_ASSERT_EQUAL(CS6, tios_result.c_cflag & CS6);
TEST_ASSERT_EQUAL(ESP_OK, uart_get_word_length(UART_NUM_1, &data_bit));
TEST_ASSERT_EQUAL(UART_DATA_6_BITS, data_bit);
TEST_ASSERT_EQUAL(0, tios_result.c_cflag & CSTOPB);
TEST_ASSERT_EQUAL(ESP_OK, uart_get_stop_bits(UART_NUM_1, &stop_bits));
TEST_ASSERT_EQUAL(UART_STOP_BITS_1, stop_bits);
TEST_ASSERT_EQUAL(ESP_OK, uart_get_parity(UART_NUM_1, &parity_mode));
TEST_ASSERT_EQUAL(UART_PARITY_DISABLE, parity_mode);
memset(&tios_result, 0xFF, sizeof(struct termios));
}
{
uart_stop_bits_t stop_bits;
uart_parity_t parity_mode;
tios.c_cflag |= CSTOPB;
tios.c_cflag |= (PARENB | PARODD);
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
tios.c_cflag &= (~(CSTOPB | PARENB | PARODD));
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
TEST_ASSERT_EQUAL(CSTOPB, tios_result.c_cflag & CSTOPB);
TEST_ASSERT_EQUAL(ESP_OK, uart_get_stop_bits(UART_NUM_1, &stop_bits));
TEST_ASSERT_EQUAL(UART_STOP_BITS_2, stop_bits);
TEST_ASSERT_EQUAL(ESP_OK, uart_get_parity(UART_NUM_1, &parity_mode));
TEST_ASSERT_EQUAL(UART_PARITY_ODD, parity_mode);
memset(&tios_result, 0xFF, sizeof(struct termios));
}
{
uint32_t baudrate;
tios.c_cflag &= (~BOTHER);
tios.c_cflag |= CBAUD;
tios.c_ispeed = tios.c_ospeed = B38400;
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
TEST_ASSERT_EQUAL(CBAUD, tios_result.c_cflag & CBAUD);
TEST_ASSERT_EQUAL(B38400, tios_result.c_ispeed);
TEST_ASSERT_EQUAL(B38400, tios_result.c_ospeed);
TEST_ASSERT_EQUAL(ESP_OK, uart_get_baudrate(UART_NUM_1, &baudrate));
TEST_ASSERT_EQUAL(38400, baudrate);
tios.c_cflag |= CBAUDEX;
tios.c_ispeed = tios.c_ospeed = B230400;
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
TEST_ASSERT_EQUAL(BOTHER, tios_result.c_cflag & BOTHER);
// Setting the speed to 230400 will set it actually to 230423
TEST_ASSERT_EQUAL(230423, tios_result.c_ispeed);
TEST_ASSERT_EQUAL(230423, tios_result.c_ospeed);
TEST_ASSERT_EQUAL(ESP_OK, uart_get_baudrate(UART_NUM_1, &baudrate));
TEST_ASSERT_EQUAL(230423, baudrate);
tios.c_cflag |= BOTHER;
tios.c_ispeed = tios.c_ospeed = 213;
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
TEST_ASSERT_EQUAL(BOTHER, tios_result.c_cflag & BOTHER);
TEST_ASSERT_EQUAL(213, tios_result.c_ispeed);
TEST_ASSERT_EQUAL(213, tios_result.c_ospeed);
TEST_ASSERT_EQUAL(ESP_OK, uart_get_baudrate(UART_NUM_1, &baudrate));
TEST_ASSERT_EQUAL(213, baudrate);
memset(&tios_result, 0xFF, sizeof(struct termios));
}
esp_vfs_dev_uart_use_nonblocking(1);
close(uart_fd);
uart_driver_delete(UART_NUM_1);
}
#endif // CONFIG_SUPPORT_TERMIOS

View File

@ -994,3 +994,103 @@ void esp_vfs_select_triggered_isr(SemaphoreHandle_t *signal_sem, BaseType_t *wok
}
}
}
#ifdef CONFIG_SUPPORT_TERMIOS
int tcgetattr(int fd, struct termios *p)
{
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
const int local_fd = get_local_fd(vfs, fd);
struct _reent* r = __getreent();
if (vfs == NULL || local_fd < 0) {
__errno_r(r) = EBADF;
return -1;
}
int ret;
CHECK_AND_CALL(ret, r, vfs, tcgetattr, local_fd, p);
return ret;
}
int tcsetattr(int fd, int optional_actions, const struct termios *p)
{
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
const int local_fd = get_local_fd(vfs, fd);
struct _reent* r = __getreent();
if (vfs == NULL || local_fd < 0) {
__errno_r(r) = EBADF;
return -1;
}
int ret;
CHECK_AND_CALL(ret, r, vfs, tcsetattr, local_fd, optional_actions, p);
return ret;
}
int tcdrain(int fd)
{
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
const int local_fd = get_local_fd(vfs, fd);
struct _reent* r = __getreent();
if (vfs == NULL || local_fd < 0) {
__errno_r(r) = EBADF;
return -1;
}
int ret;
CHECK_AND_CALL(ret, r, vfs, tcdrain, local_fd);
return ret;
}
int tcflush(int fd, int select)
{
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
const int local_fd = get_local_fd(vfs, fd);
struct _reent* r = __getreent();
if (vfs == NULL || local_fd < 0) {
__errno_r(r) = EBADF;
return -1;
}
int ret;
CHECK_AND_CALL(ret, r, vfs, tcflush, local_fd, select);
return ret;
}
int tcflow(int fd, int action)
{
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
const int local_fd = get_local_fd(vfs, fd);
struct _reent* r = __getreent();
if (vfs == NULL || local_fd < 0) {
__errno_r(r) = EBADF;
return -1;
}
int ret;
CHECK_AND_CALL(ret, r, vfs, tcflow, local_fd, action);
return ret;
}
pid_t tcgetsid(int fd)
{
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
const int local_fd = get_local_fd(vfs, fd);
struct _reent* r = __getreent();
if (vfs == NULL || local_fd < 0) {
__errno_r(r) = EBADF;
return -1;
}
int ret;
CHECK_AND_CALL(ret, r, vfs, tcgetsid, local_fd);
return ret;
}
int tcsendbreak(int fd, int duration)
{
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
const int local_fd = get_local_fd(vfs, fd);
struct _reent* r = __getreent();
if (vfs == NULL || local_fd < 0) {
__errno_r(r) = EBADF;
return -1;
}
int ret;
CHECK_AND_CALL(ret, r, vfs, tcsendbreak, local_fd, duration);
return ret;
}
#endif // CONFIG_SUPPORT_TERMIOS

View File

@ -80,14 +80,15 @@ static esp_line_endings_t s_tx_mode =
#endif
// Newline conversion mode when receiving
static esp_line_endings_t s_rx_mode =
static esp_line_endings_t s_rx_mode[UART_NUM] = { [0 ... UART_NUM-1] =
#if CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF
ESP_LINE_ENDINGS_CRLF;
ESP_LINE_ENDINGS_CRLF
#elif CONFIG_NEWLIB_STDIN_LINE_ENDING_CR
ESP_LINE_ENDINGS_CR;
ESP_LINE_ENDINGS_CR
#else
ESP_LINE_ENDINGS_LF;
ESP_LINE_ENDINGS_LF
#endif
};
static void uart_end_select();
@ -213,9 +214,9 @@ static ssize_t uart_read(int fd, void* data, size_t size)
while (received < size) {
int c = uart_read_char(fd);
if (c == '\r') {
if (s_rx_mode == ESP_LINE_ENDINGS_CR) {
if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CR) {
c = '\n';
} else if (s_rx_mode == ESP_LINE_ENDINGS_CRLF) {
} else if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CRLF) {
/* look ahead */
int c2 = uart_read_char(fd);
if (c2 == NONE) {
@ -420,6 +421,456 @@ static void uart_end_select()
_lock_release(&s_one_select_lock);
}
#ifdef CONFIG_SUPPORT_TERMIOS
static int uart_tcsetattr(int fd, int optional_actions, const struct termios *p)
{
if (fd < 0 || fd >= UART_NUM) {
errno = EBADF;
return -1;
}
if (p == NULL) {
errno = EINVAL;
return -1;
}
switch (optional_actions) {
case TCSANOW:
// nothing to do
break;
case TCSADRAIN:
if (uart_wait_tx_done(fd, portMAX_DELAY) != ESP_OK) {
errno = EINVAL;
return -1;
}
// intentional fall-through to the next case
case TCSAFLUSH:
if (uart_flush_input(fd) != ESP_OK) {
errno = EINVAL;
return -1;
}
break;
default:
errno = EINVAL;
return -1;
}
if (p->c_iflag & IGNCR) {
s_rx_mode[fd] = ESP_LINE_ENDINGS_CRLF;
} else if (p->c_iflag & ICRNL) {
s_rx_mode[fd] = ESP_LINE_ENDINGS_CR;
} else {
s_rx_mode[fd] = ESP_LINE_ENDINGS_LF;
}
// output line endings are not supported because there is no alternative in termios for converting LF to CR
{
uart_word_length_t data_bits;
const tcflag_t csize_bits = p->c_cflag & CSIZE;
switch (csize_bits) {
case CS5:
data_bits = UART_DATA_5_BITS;
break;
case CS6:
data_bits = UART_DATA_6_BITS;
break;
case CS7:
data_bits = UART_DATA_7_BITS;
break;
case CS8:
data_bits = UART_DATA_8_BITS;
break;
default:
errno = EINVAL;
return -1;
}
if (uart_set_word_length(fd, data_bits) != ESP_OK) {
errno = EINVAL;
return -1;
}
}
if (uart_set_stop_bits(fd, (p->c_cflag & CSTOPB) ? UART_STOP_BITS_2 : UART_STOP_BITS_1) != ESP_OK) {
errno = EINVAL;
return -1;
}
if (uart_set_parity(fd, (p->c_cflag & PARENB) ?
((p->c_cflag & PARODD) ? UART_PARITY_ODD : UART_PARITY_EVEN)
:
UART_PARITY_DISABLE) != ESP_OK) {
errno = EINVAL;
return -1;
}
if (p->c_cflag & (CBAUD | CBAUDEX)) {
if (p->c_ispeed != p->c_ospeed) {
errno = EINVAL;
return -1;
} else {
uint32_t b;
if (p->c_cflag & BOTHER) {
b = p->c_ispeed;
} else {
switch (p->c_ispeed) {
case B0:
b = 0;
break;
case B50:
b = 50;
break;
case B75:
b = 75;
break;
case B110:
b = 110;
break;
case B134:
b = 134;
break;
case B150:
b = 150;
break;
case B200:
b = 200;
break;
case B300:
b = 300;
break;
case B600:
b = 600;
break;
case B1200:
b = 1200;
break;
case B1800:
b = 1800;
break;
case B2400:
b = 2400;
break;
case B4800:
b = 4800;
break;
case B9600:
b = 9600;
break;
case B19200:
b = 19200;
break;
case B38400:
b = 38400;
break;
case B57600:
b = 57600;
break;
case B115200:
b = 115200;
break;
case B230400:
b = 230400;
break;
case B460800:
b = 460800;
break;
case B500000:
b = 500000;
break;
case B576000:
b = 576000;
break;
case B921600:
b = 921600;
break;
case B1000000:
b = 1000000;
break;
case B1152000:
b = 1152000;
break;
case B1500000:
b = 1500000;
break;
case B2000000:
b = 2000000;
break;
case B2500000:
b = 2500000;
break;
case B3000000:
b = 3000000;
break;
case B3500000:
b = 3500000;
break;
case B4000000:
b = 4000000;
break;
default:
errno = EINVAL;
return -1;
}
}
if (uart_set_baudrate(fd, b) != ESP_OK) {
errno = EINVAL;
return -1;
}
}
}
return 0;
}
static int uart_tcgetattr(int fd, struct termios *p)
{
if (fd < 0 || fd >= UART_NUM) {
errno = EBADF;
return -1;
}
if (p == NULL) {
errno = EINVAL;
return -1;
}
memset(p, 0, sizeof(struct termios));
if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CRLF) {
p->c_iflag |= IGNCR;
} else if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CR) {
p->c_iflag |= ICRNL;
}
{
uart_word_length_t data_bits;
if (uart_get_word_length(fd, &data_bits) != ESP_OK) {
errno = EINVAL;
return -1;
}
p->c_cflag &= (~CSIZE);
switch (data_bits) {
case UART_DATA_5_BITS:
p->c_cflag |= CS5;
break;
case UART_DATA_6_BITS:
p->c_cflag |= CS6;
break;
case UART_DATA_7_BITS:
p->c_cflag |= CS7;
break;
case UART_DATA_8_BITS:
p->c_cflag |= CS8;
break;
default:
errno = ENOSYS;
return -1;
}
}
{
uart_stop_bits_t stop_bits;
if (uart_get_stop_bits(fd, &stop_bits) != ESP_OK) {
errno = EINVAL;
return -1;
}
switch (stop_bits) {
case UART_STOP_BITS_1:
// nothing to do
break;
case UART_STOP_BITS_2:
p->c_cflag |= CSTOPB;
break;
default:
// UART_STOP_BITS_1_5 is unsupported by termios
errno = ENOSYS;
return -1;
}
}
{
uart_parity_t parity_mode;
if (uart_get_parity(fd, &parity_mode) != ESP_OK) {
errno = EINVAL;
return -1;
}
switch (parity_mode) {
case UART_PARITY_EVEN:
p->c_cflag |= PARENB;
break;
case UART_PARITY_ODD:
p->c_cflag |= (PARENB | PARODD);
break;
case UART_PARITY_DISABLE:
// nothing to do
break;
default:
errno = ENOSYS;
return -1;
}
}
{
uint32_t baudrate;
if (uart_get_baudrate(fd, &baudrate) != ESP_OK) {
errno = EINVAL;
return -1;
}
p->c_cflag |= (CBAUD | CBAUDEX);
speed_t sp;
switch (baudrate) {
case 0:
sp = B0;
break;
case 50:
sp = B50;
break;
case 75:
sp = B75;
break;
case 110:
sp = B110;
break;
case 134:
sp = B134;
break;
case 150:
sp = B150;
break;
case 200:
sp = B200;
break;
case 300:
sp = B300;
break;
case 600:
sp = B600;
break;
case 1200:
sp = B1200;
break;
case 1800:
sp = B1800;
break;
case 2400:
sp = B2400;
break;
case 4800:
sp = B4800;
break;
case 9600:
sp = B9600;
break;
case 19200:
sp = B19200;
break;
case 38400:
sp = B38400;
break;
case 57600:
sp = B57600;
break;
case 115200:
sp = B115200;
break;
case 230400:
sp = B230400;
break;
case 460800:
sp = B460800;
break;
case 500000:
sp = B500000;
break;
case 576000:
sp = B576000;
break;
case 921600:
sp = B921600;
break;
case 1000000:
sp = B1000000;
break;
case 1152000:
sp = B1152000;
break;
case 1500000:
sp = B1500000;
break;
case 2000000:
sp = B2000000;
break;
case 2500000:
sp = B2500000;
break;
case 3000000:
sp = B3000000;
break;
case 3500000:
sp = B3500000;
break;
case 4000000:
sp = B4000000;
break;
default:
p->c_cflag |= BOTHER;
sp = baudrate;
break;
}
p->c_ispeed = p->c_ospeed = sp;
}
return 0;
}
static int uart_tcdrain(int fd)
{
if (fd < 0 || fd >= UART_NUM) {
errno = EBADF;
return -1;
}
if (uart_wait_tx_done(fd, portMAX_DELAY) != ESP_OK) {
errno = EINVAL;
return -1;
}
return 0;
}
static int uart_tcflush(int fd, int select)
{
if (fd < 0 || fd >= UART_NUM) {
errno = EBADF;
return -1;
}
if (select == TCIFLUSH) {
if (uart_flush_input(fd) != ESP_OK) {
errno = EINVAL;
return -1;
}
} else {
// output flushing is not supported
errno = EINVAL;
return -1;
}
return 0;
}
#endif // CONFIG_SUPPORT_TERMIOS
void esp_vfs_dev_uart_register()
{
esp_vfs_t vfs = {
@ -433,13 +884,21 @@ void esp_vfs_dev_uart_register()
.access = &uart_access,
.start_select = &uart_start_select,
.end_select = &uart_end_select,
#ifdef CONFIG_SUPPORT_TERMIOS
.tcsetattr = &uart_tcsetattr,
.tcgetattr = &uart_tcgetattr,
.tcdrain = &uart_tcdrain,
.tcflush = &uart_tcflush,
#endif // CONFIG_SUPPORT_TERMIOS
};
ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL));
}
void esp_vfs_dev_uart_set_rx_line_endings(esp_line_endings_t mode)
{
s_rx_mode = mode;
for (int i = 0; i < UART_NUM; ++i) {
s_rx_mode[i] = mode;
}
}
void esp_vfs_dev_uart_set_tx_line_endings(esp_line_endings_t mode)

View File

@ -39,26 +39,9 @@ unsigned long os_random(void)
return esp_random();
}
unsigned long r_rand(void) __attribute__((alias("os_random")));
int os_get_random(unsigned char *buf, size_t len)
{
int i, j;
unsigned long tmp;
for (i = 0; i < ((len + 3) & ~3) / 4; i++) {
tmp = r_rand();
for (j = 0; j < 4; j++) {
if ((i * 4 + j) < len) {
buf[i * 4 + j] = (uint8_t)(tmp >> (j * 8));
} else {
break;
}
}
}
esp_fill_random(buf, len);
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
docs/_static/mesh-beacon-frame-rssi.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/_static/mesh-network-building.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
docs/_static/mesh-node-types.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/_static/mesh-packet.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/_static/mesh-root-node-failure.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/_static/mesh-tree-topology.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

View File

@ -30,6 +30,11 @@ builddir = builddir
if 'BUILDDIR' in os.environ:
builddir = os.environ['BUILDDIR']
def call_with_python(cmd):
# using sys.executable ensures that the scripts are called with the same Python interpreter
if os.system('{} {}'.format(sys.executable, cmd)) != 0:
raise RuntimeError('{} failed'.format(cmd))
# Call Doxygen to get XML files from the header files
print("Calling Doxygen to generate latest XML files")
if os.system("doxygen ../Doxyfile") != 0:
@ -40,8 +45,7 @@ if os.system("doxygen ../Doxyfile") != 0:
copy_if_modified('xml/', 'xml_in/')
# Generate 'api_name.inc' files using the XML files by Doxygen
if os.system('python ../gen-dxd.py') != 0:
raise RuntimeError('gen-dxd.py failed')
call_with_python('../gen-dxd.py')
# Generate 'kconfig.inc' file from components' Kconfig files
print("Generating kconfig.inc from kconfig contents")
@ -49,22 +53,19 @@ kconfig_inc_path = '{}/inc/kconfig.inc'.format(builddir)
temp_sdkconfig_path = '{}/sdkconfig.tmp'.format(builddir)
kconfigs = subprocess.check_output(["find", "../../components", "-name", "Kconfig"]).decode()
kconfig_projbuilds = subprocess.check_output(["find", "../../components", "-name", "Kconfig.projbuild"]).decode()
confgen_args = ["python",
call_with_python(" ".join(
"../../tools/kconfig_new/confgen.py",
"--kconfig", "../../Kconfig",
"--config", temp_sdkconfig_path,
"--create-config-if-missing",
"--env", "COMPONENT_KCONFIGS={}".format(kconfigs),
"--env", "COMPONENT_KCONFIGS_PROJBUILD={}".format(kconfig_projbuilds),
"--output", "docs", kconfig_inc_path + '.in'
]
subprocess.check_call(confgen_args)
"--output", "docs", kconfig_inc_path + '.in'))
copy_if_modified(kconfig_inc_path + '.in', kconfig_inc_path)
# Generate 'esp_err_defs.inc' file with ESP_ERR_ error code definitions
esp_err_inc_path = '{}/inc/esp_err_defs.inc'.format(builddir)
if os.system('python ../../tools/gen_esp_err_to_name.py --rst_output ' + esp_err_inc_path + '.in') != 0:
raise RuntimeError('gen_esp_err_to_name.py failed')
call_with_python('../../tools/gen_esp_err_to_name.py --rst_output ' + esp_err_inc_path + '.in')
copy_if_modified(esp_err_inc_path + '.in', esp_err_inc_path)
# Generate version-related includes
@ -73,8 +74,7 @@ copy_if_modified(esp_err_inc_path + '.in', esp_err_inc_path)
def generate_version_specific_includes(app):
print("Generating version-specific includes...")
version_tmpdir = '{}/version_inc'.format(builddir)
if os.system('python ../gen-version-specific-includes.py {} {}'.format(app.config.language, version_tmpdir)):
raise RuntimeError('gen-version-specific-includes.py failed')
call_with_python('../gen-version-specific-includes.py {} {}'.format(app.config.language, version_tmpdir))
copy_if_modified(version_tmpdir, '{}/inc'.format(builddir))

View File

@ -28,7 +28,7 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) -w
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext dependencies version-specific-includes
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext dependencies version-specific-includes check_python_packages
help:
@echo "Please use \`make <target>\' where <target> is one of"
@ -58,38 +58,44 @@ help:
clean:
rm -rf $(BUILDDIR)/*
html:
# Notify users when some of the required python packages are not installed.
# Note: This is intended to help developers who generate the documentation on their local machine. Read The Docs uses
# the requirements.txt file directly and calls sphinx also directly without the use of the makefile!
check_python_packages:
$(IDF_PATH)/tools/check_python_dependencies.py -r $(IDF_PATH)/docs/requirements.txt
html: | check_python_packages
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
dirhtml: | check_python_packages
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
singlehtml: | check_python_packages
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
pickle: | check_python_packages
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
json: | check_python_packages
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
htmlhelp: | check_python_packages
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
qthelp: | check_python_packages
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
@ -98,7 +104,7 @@ qthelp:
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhc"
devhelp:
devhelp: | check_python_packages
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@ -107,70 +113,70 @@ devhelp:
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ReadtheDocsTemplate"
@echo "# devhelp"
epub:
epub: | check_python_packages
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
latex: | check_python_packages
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
latexpdf: | check_python_packages
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
latexpdfja: | check_python_packages
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
text: | check_python_packages
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
man: | check_python_packages
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
texinfo: | check_python_packages
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
info: | check_python_packages
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
gettext: | check_python_packages
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
changes: | check_python_packages
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
linkcheck: | check_python_packages
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
gh-linkcheck:
gh-linkcheck: | check_python_packages
@echo "Checking for hardcoded GitHub links"
@if (find ../ -name '*.rst' | xargs grep \
'https://github.com/espressif/esp-idf/tree\|https://github.com/espressif/esp-idf/blob\|https://github.com/espressif/esp-idf/raw'\
@ -194,17 +200,17 @@ gh-linkcheck:
fi
@echo "No hardcoded links found"
doctest:
doctest: | check_python_packages
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
xml: | check_python_packages
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
pseudoxml: | check_python_packages
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@ -25,6 +25,6 @@ API Guides
Console Component <console>
ROM debug console <romconsole>
WiFi Driver <wifi>
Mesh Stack <mesh>
ESP-MESH <mesh>
BluFi <blufi>
External SPI-connected RAM <external-ram>

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,266 @@
Mesh
=====
ESP-MESH Programming Guide
==========================
This is a programming guide for ESP-MESH, including the API reference and coding
examples. This guide is split into the following parts:
1. :ref:`mesh-programming-model`
2. :ref:`mesh-writing-mesh-application`
3. :ref:`mesh-application-examples`
4. :ref:`mesh-api-reference`
For documentation regarding the ESP-MESH protocol, please see the
:doc:`ESP-MESH API Guide<../../api-guides/mesh>`.
.. ---------------------- ESP-MESH Programming Model --------------------------
.. _mesh-programming-model:
ESP-MESH Programming Model
--------------------------
Software Stack
^^^^^^^^^^^^^^
The ESP-MESH software stack is built atop the Wi-Fi Driver/FreeRTOS and may use
the LwIP Stack in some instances (i.e. the root node). The following diagram
illustrates the ESP-MESH software stack.
.. _mesh-going-to-software-stack:
.. figure:: ../../../_static/mesh-software-stack.png
:align: center
:alt: ESP-MESH Software Stack
:figclass: align-center
ESP-MESH Software Stack
System Events
^^^^^^^^^^^^^
An application interfaces with ESP-MESH via **ESP-MESH Events**. Since ESP-MESH
is built atop the Wi-Fi stack, it is also possible for the application to interface
with the Wi-Fi driver via the **Wi-Fi Event Task**. The following diagram illustrates
the interfaces for the various System Events in an ESP-MESH application.
.. figure:: ../../../_static/mesh-events-delivery.png
:align: center
:alt: ESP-MESH System Events Delivery
:figclass: align-center
ESP-MESH System Events Delivery
The :cpp:type:`mesh_event_id_t` defines all possible ESP-MESH system events and
can indicate events such as the connection/disconnection of parent/child. Before
ESP-MESH system events can be used, the application must register a **Mesh Event
Callback** via :cpp:func:`esp_mesh_set_config`. The callback is used to receive
events from the ESP-MESH stack as well as the LwIP Stack and should contain handlers
for each event relevant to the application.
Typical use cases of system events include using events such as
:cpp:enumerator:`MESH_EVENT_PARENT_CONNECTED` and :cpp:enumerator:`MESH_EVENT_CHILD_CONNECTED`
to indicate when a node can begin transmitting data upstream and downstream respectively. Likewise,
:cpp:enumerator:`MESH_EVENT_ROOT_GOT_IP` and :cpp:enumerator:`MESH_EVENT_ROOT_LOST_IP` can be
used to indicate when the root node can and cannot transmit data to the external IP
network.
.. warning::
When using ESP-MESH under self-organized mode, users must ensure that no calls
to Wi-Fi API are made. This is due to the fact that the self-organizing mode
will internally make Wi-Fi API calls to connect/disconnect/scan etc.
**Any Wi-Fi calls from the application (including calls from callbacks and
handlers of Wi-Fi events) may interfere with ESP-MESH's self-organizing behavior**.
Therefore, user's should not call Wi-Fi APIs after :cpp:func:`esp_mesh_start`
is called, and before :cpp:func:`esp_mesh_stop` is called.
LwIP & ESP-MESH
^^^^^^^^^^^^^^^
The application can access the ESP-MESH stack directly without having to go through
the LwIP stack. The LwIP stack is only required by the root node to transmit/receive
data to/from an external IP network. However, since every node can potentially
become the root node (due to automatic root node selection), each node must still
initialize the LwIP stack.
**Each node is required to initialize LwIP by calling** :cpp:func:`tcpip_adapter_init`.
In order to prevent non-root node access to LwIP, the application should stop the
following services after LwIP initialization:
- DHCP server service on the softAP interface.
- DHCP client service on the station interface.
The following code snippet demonstrates how to initialize LwIP for ESP-MESH applications.
.. code-block:: c
/* tcpip initialization */
tcpip_adapter_init();
/*
* for mesh
* stop DHCP server on softAP interface by default
* stop DHCP client on station interface by default
*/
ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
/* do not specify system event callback, use NULL instead. */
ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL));
.. note::
ESP-MESH requires a root node to be connected with a router. Therefore, in
the event that a node becomes the root, **the corresponding handler must start
the DHCP client service and immediately obtain an IP address**. Doing so will
allow other nodes to begin transmitting/receiving packets to/from the external
IP network. However, this step is unnecessary if static IP settings are used.
.. ---------------------- Writing a Mesh Application --------------------------
.. _mesh-writing-mesh-application:
Writing an ESP-MESH Application
-------------------------------
The prerequisites for starting ESP-MESH is to initialize LwIP and Wi-Fi, The
following code snippet demonstrates the necessary prerequisite steps before
ESP-MESH itself can be initialized.
.. code-block:: c
tcpip_adapter_init();
/*
* for mesh
* stop DHCP server on softAP interface by default
* stop DHCP client on station interface by default
*/
ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
/* do not specify system event callback, use NULL instead. */
ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL));
/* Wi-Fi initialization */
wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&config));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
ESP_ERROR_CHECK(esp_wifi_start());
After initializing LwIP and Wi-Fi, the process of getting an ESP-MESH network
up and running can be summarized into the following three steps:
1. :ref:`mesh-initialize-mesh`
2. :ref:`mesh-configuring-mesh`
3. :ref:`mesh-start-mesh`
.. _mesh-initialize-mesh:
Initialize Mesh
^^^^^^^^^^^^^^^
The following code snippet demonstrates how to initialize ESP-MESH
.. code-block:: c
/* mesh initialization */
ESP_ERROR_CHECK(esp_mesh_init());
.. _mesh-configuring-mesh:
Configuring an ESP-MESH Network
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. todo - Add note about unified configuration
ESP-MESH is configured via :cpp:func:`esp_mesh_set_config` which receives its arguments
using the :cpp:type:`mesh_cfg_t` structure. The structure contains the following
parameters used to configure ESP-MESH:
+------------------+-------------------------------------+
| Parameter | Description |
+==================+=====================================+
| Channel | Range from 1 to 14 |
+------------------+-------------------------------------+
| Event Callback | Callback for Mesh Events, |
| | see :cpp:type:`mesh_event_cb_t` |
+------------------+-------------------------------------+
| Mesh ID | ID of ESP-MESH Network, |
| | see :cpp:type:`mesh_addr_t` |
+------------------+-------------------------------------+
| Router | Router Configuration, |
| | see :cpp:type:`mesh_router_t` |
+------------------+-------------------------------------+
| Mesh AP | Mesh AP Configuration, |
| | see :cpp:type:`mesh_ap_cfg_t` |
+------------------+-------------------------------------+
| Crypto Functions | Crypto Functions for Mesh IE, |
| | see :cpp:type:`mesh_crypto_funcs_t` |
+------------------+-------------------------------------+
The following code snippet demonstrates how to configure ESP-MESH.
.. code-block:: c
/* Enable the Mesh IE encryption by default */
mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT();
/* mesh ID */
memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6);
/* mesh event callback */
cfg.event_cb = &mesh_event_handler;
/* channel (must match the router's channel) */
cfg.channel = CONFIG_MESH_CHANNEL;
/* router */
cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID);
memcpy((uint8_t *) &cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len);
memcpy((uint8_t *) &cfg.router.password, CONFIG_MESH_ROUTER_PASSWD,
strlen(CONFIG_MESH_ROUTER_PASSWD));
/* mesh softAP */
cfg.mesh_ap.max_connection = CONFIG_MESH_AP_CONNECTIONS;
memcpy((uint8_t *) &cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD,
strlen(CONFIG_MESH_AP_PASSWD));
ESP_ERROR_CHECK(esp_mesh_set_config(&cfg));
.. _mesh-start-mesh:
Start Mesh
^^^^^^^^^^
The following code snippet demonstrates how to start ESP-MESH.
.. code-block:: c
/* mesh start */
ESP_ERROR_CHECK(esp_mesh_start());
After starting ESP-MESH, the application should check for ESP-MESH events to determine
when it has connected to the network. After connecting, the application can start
transmitting and receiving packets over the ESP-MESH network using
:cpp:func:`esp_mesh_send` and :cpp:func:`esp_mesh_recv`.
.. --------------------- ESP-MESH Application Examples ------------------------
.. _mesh-application-examples:
Application Examples
--------------------
See :example:`mesh` directory of ESP-IDF examples that contains the following applications.
ESP-IDF contains these ESP-MESH example projects:
:example:`The Internal Communication Example<mesh/internal_communication>` demonstrates
how to setup a ESP-MESH network and have the root node send a data packet to
every node within the network.
:example:`The Manual Networking Example<mesh/manual_networking>` demonstrates
how to use ESP-MESH without the self-organizing features. This example shows how
to program a node to manually scan for a list of potential parent nodes and select
a parent node based on custom criteria.
.. ------------------------- ESP-MESH API Reference ---------------------------
.. _mesh-api-reference:
API Reference
--------------

View File

@ -574,6 +574,23 @@ use of the :cpp:func:`can_stop` and :cpp:func:`can_driver_uninstall` functions.
return;
}
Multiple ID Filter Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The acceptance mask in :cpp:type:`can_filter_config_t` can be configured such that
two or more IDs will be accepted for a single filter. For a particular filter to
accept multiple IDs, the conflicting bit positions amongst the IDs must be set
in the acceptance mask. The acceptance code can be set to any one of the IDs.
The following example shows how the calculate the acceptance mask given multiple
IDs::
ID1 = 11'b101 1010 0000
ID2 = 11'b101 1010 0001
ID3 = 11'b101 1010 0100
ID4 = 11'b101 1010 1000
//Acceptance Mask
MASK = 11'b000 0000 1101
Application Examples
^^^^^^^^^^^^^^^^^^^^
@ -581,19 +598,19 @@ Application Examples
**Network Example:** The CAN Network example demonstrates communication between
two ESP32s using the CAN driver API. One CAN node acts as a network master initiate
and ceasing the transfer of a data from another CAN node acting as a network slave.
The example can be found via :example:`examples/peripheral/can/can_network`.
The example can be found via :example:`peripherals/can/can_network`.
**Alert and Recovery Example:** This example demonstrates how to use the CAN driver's
alert and bus recovery API. The example purposely introduces errors on the CAN
bus to put the CAN controller into the Bus-Off state. An alert is used to detect
the Bus-Off state and trigger the bus recovery process. The example can be found
via :example:`examples/peripheral/can/can_alert_and_recovery`.
via :example:`peripherals/can/can_alert_and_recovery`.
**Self Test Example:** This example uses the No Acknowledge Mode and Self Reception
Request to cause the CAN controller to send and simultaneously receive a series
of messages. This example can be used to verify if the connections between the CAN
controller and the external transceiver are working correctly. The example can be
found via :example:`examples/peripheral/can/can_self_test`.
found via :example:`peripherals/can/can_self_test`.
.. ---------------------------- API Reference ----------------------------------

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