Merge branch 'master' into feature/cmake

This commit is contained in:
Angus Gratton 2018-08-30 12:30:09 +08:00 committed by Angus Gratton
commit a9c4ed7139
201 changed files with 5331 additions and 2118 deletions

View File

@ -315,7 +315,7 @@ test_fatfs_on_host:
- cd components/fatfs/test_fatfs_host/
- make test
test_mdns_fuzzer_on_host:
.host_fuzzer_test_template: &host_fuzzer_test_template
stage: host_test
image: $CI_DOCKER_REGISTRY/afl-fuzzer-test
tags:
@ -324,21 +324,47 @@ test_mdns_fuzzer_on_host:
artifacts:
when: always
paths:
- components/mdns/test_afl_fuzz_host/out/crashes
- ${FUZZER_TEST_DIR}/out/crashes
- ${FUZZER_TEST_DIR}/fuzz_output.log
expire_in: 1 mos
only:
# can only be triggered
- triggers
variables:
BOT_NEEDS_TRIGGER_BY_NAME: 1
script:
- export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 && export AFL_SKIP_CPUFREQ=1
- cd components/mdns/test_afl_fuzz_host/
- cd ${FUZZER_TEST_DIR}
# run AFL fuzzer for one hour
- ( make fuzz || pkill sleep ) &
- ( ( make ${FUZZER_PARAMS} fuzz | tee fuzz_output.log | grep -v '\(Fuzzing test case\|Entering queue cycle\)' ) || pkill sleep ) &
- ( sleep 3600 || mkdir -p out/crashes/env_failed ) && pkill afl-fuz
# check no crashes found
- "[ -z `ls out/crashes/` ] || exit 1"
- test -z "$(ls out/crashes/)" || exit 1
test_mdns_fuzzer_on_host:
<<: *host_fuzzer_test_template
variables:
BOT_NEEDS_TRIGGER_BY_NAME: 1
FUZZER_TEST_DIR: components/mdns/test_afl_fuzz_host
test_lwip_dns_fuzzer_on_host:
<<: *host_fuzzer_test_template
variables:
BOT_NEEDS_TRIGGER_BY_NAME: 1
FUZZER_TEST_DIR: components/lwip/test_afl_host
FUZZER_PARAMS: MODE=dns
test_lwip_dhcp_fuzzer_on_host:
<<: *host_fuzzer_test_template
variables:
BOT_NEEDS_TRIGGER_BY_NAME: 1
FUZZER_TEST_DIR: components/lwip/test_afl_host
FUZZER_PARAMS: MODE=dhcp_client
test_lwip_dhcps_fuzzer_on_host:
<<: *host_fuzzer_test_template
variables:
BOT_NEEDS_TRIGGER_BY_NAME: 1
FUZZER_TEST_DIR: components/lwip/test_afl_host
FUZZER_PARAMS: MODE=dhcp_server
test_spiffs_on_host:
<<: *host_test_template
@ -385,14 +411,30 @@ test_idf_monitor:
expire_in: 1 week
script:
- cd ${IDF_PATH}/tools/test_idf_monitor
- source /opt/pyenv/activate
- pyenv global 2.7.15
- ./run_test_idf_monitor.py
- pyenv global 3.4.8
- ./run_test_idf_monitor.py
- pyenv global system
test_esp_err_to_name_on_host:
<<: *host_test_template
artifacts:
when: on_failure
paths:
- components/esp32/esp_err_to_name.c
expire_in: 1 week
script:
- cd tools/
- source /opt/pyenv/activate
- pyenv global 2.7.15
- ./gen_esp_err_to_name.py
- git diff --exit-code -- ../components/esp32/esp_err_to_name.c || (echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1)
- pyenv global 3.4.8
- ./gen_esp_err_to_name.py
- git diff --exit-code -- ../components/esp32/esp_err_to_name.c || (echo 'Differences found between running under Python 2 and 3.'; exit 1)
- pyenv global system
push_to_github:
stage: deploy
@ -931,6 +973,18 @@ UT_001_34:
- ESP32_IDF
- UT_T1_1
UT_001_35:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
UT_001_36:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
UT_002_01:
<<: *unit_test_template
tags:

View File

@ -41,6 +41,7 @@ static inline void esp_apptrace_tmo_init(esp_apptrace_tmo_t *tmo, uint32_t user_
{
tmo->start = portGET_RUN_TIME_COUNTER_VALUE();
tmo->tmo = user_tmo;
tmo->elapsed = 0;
}
/**

View File

@ -1,22 +1,55 @@
#
# Generate partition binary
#
.PHONY: erase_ota blank_ota_data
.PHONY: dump_otadata erase_ota blank_ota_data
GEN_EMPTY_PART := $(PYTHON) $(COMPONENT_PATH)/gen_empty_partition.py
BLANK_OTA_DATA_FILE = $(BUILD_DIR_BASE)/ota_data_initial.bin
PARTITION_TABLE_LEN := 0xC00
OTADATA_LEN := 0x2000
PARTITION_TABLE_ONCHIP_BIN_PATH := $(call dequote,$(abspath $(BUILD_DIR_BASE)))
PARTITION_TABLE_ONCHIP_BIN_NAME := "onchip_partition.bin"
OTADATA_ONCHIP_BIN_NAME := "onchip_otadata.bin"
PARTITION_TABLE_ONCHIP_BIN := $(PARTITION_TABLE_ONCHIP_BIN_PATH)/$(call dequote,$(PARTITION_TABLE_ONCHIP_BIN_NAME))
OTADATA_ONCHIP_BIN := $(PARTITION_TABLE_ONCHIP_BIN_PATH)/$(call dequote,$(OTADATA_ONCHIP_BIN_NAME))
PARTITION_TABLE_GET_BIN_CMD = $(ESPTOOLPY_SERIAL) read_flash $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_LEN) $(PARTITION_TABLE_ONCHIP_BIN)
OTADATA_GET_BIN_CMD = $(ESPTOOLPY_SERIAL) read_flash $(OTADATA_OFFSET) $(OTADATA_LEN) $(OTADATA_ONCHIP_BIN)
GEN_OTADATA = $(IDF_PATH)/components/app_update/dump_otadata.py
ERASE_OTADATA_CMD = $(ESPTOOLPY_SERIAL) erase_region $(OTADATA_OFFSET) $(OTADATA_LEN)
# If there is no otadata partition, both OTA_DATA_OFFSET and BLANK_OTA_DATA_FILE
# expand to empty values.
ESPTOOL_ALL_FLASH_ARGS += $(OTA_DATA_OFFSET) $(BLANK_OTA_DATA_FILE)
$(PARTITION_TABLE_ONCHIP_BIN):
$(PARTITION_TABLE_GET_BIN_CMD)
onchip_otadata_get_info: $(PARTITION_TABLE_ONCHIP_BIN)
$(eval OTADATA_OFFSET:=$(shell $(GET_PART_INFO) --type data --subtype ota --offset $(PARTITION_TABLE_ONCHIP_BIN)))
@echo $(if $(OTADATA_OFFSET), $(shell export OTADATA_OFFSET), $(shell rm -f $(PARTITION_TABLE_ONCHIP_BIN));$(error "ERROR: ESP32 does not have otadata partition."))
$(OTADATA_ONCHIP_BIN):
$(OTADATA_GET_BIN_CMD)
dump_otadata: onchip_otadata_get_info $(OTADATA_ONCHIP_BIN) $(PARTITION_TABLE_ONCHIP_BIN)
@echo "otadata retrieved. Contents:"
@echo $(SEPARATOR)
$(GEN_OTADATA) $(OTADATA_ONCHIP_BIN)
@echo $(SEPARATOR)
rm -f $(PARTITION_TABLE_ONCHIP_BIN)
rm -f $(OTADATA_ONCHIP_BIN)
$(BLANK_OTA_DATA_FILE): partition_table_get_info
$(GEN_EMPTY_PART) --size $(OTA_DATA_SIZE) $(BLANK_OTA_DATA_FILE)
$(eval BLANK_OTA_DATA_FILE = $(shell if [ $(OTA_DATA_SIZE) != 0 ]; then echo $(BLANK_OTA_DATA_FILE); else echo " "; fi) )
blank_ota_data: $(BLANK_OTA_DATA_FILE)
erase_ota: partition_table_get_info
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

@ -0,0 +1,88 @@
#!/usr/bin/env python
#
# gen_otadata prints info about the otadata partition.
#
# 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.
from __future__ import print_function, division
import argparse
import os
import re
import struct
import sys
import hashlib
import binascii
__version__ = '1.0'
quiet = False
def status(msg):
""" Print status message to stderr """
if not quiet:
critical(msg)
def critical(msg):
""" Print critical message to stderr """
if not quiet:
sys.stderr.write(msg)
sys.stderr.write('\n')
def little_endian(buff, offset):
data = buff[offset:offset+4]
data.reverse()
data = ''.join(data)
return data
def main():
global quiet
parser = argparse.ArgumentParser(description='Prints otadata partition in human readable form.')
parser.add_argument('--quiet', '-q', help="Don't print status messages to stderr", action='store_true')
search_type = parser.add_mutually_exclusive_group()
parser.add_argument('input', help='Path to binary file containing otadata partition to parse.',
type=argparse.FileType('rb'))
args = parser.parse_args()
quiet = args.quiet
input = args.input.read()
hex_input_0 = binascii.hexlify(input)
hex_input_0 = map(''.join, zip(*[iter(hex_input_0)]*2))
hex_input_1 = binascii.hexlify(input[4096:])
hex_input_1 = map(''.join, zip(*[iter(hex_input_1)]*2))
print("\t%11s\t%8s |\t%8s\t%8s" %("OTA_SEQ", "CRC", "OTA_SEQ", "CRC"))
print("Firmware: 0x%s \t 0x%s |\t0x%s \t 0x%s" % (little_endian(hex_input_0, 0), little_endian(hex_input_0, 28), \
little_endian(hex_input_1, 0), little_endian(hex_input_1, 28)))
class InputError(RuntimeError):
def __init__(self, e):
super(InputError, self).__init__(e)
class ValidationError(InputError):
def __init__(self, partition, message):
super(ValidationError, self).__init__(
"Partition %s invalid: %s" % (partition.name, message))
if __name__ == '__main__':
try:
r = main()
sys.exit(r)
except InputError as e:
print(e, file=sys.stderr)
sys.exit(2)

View File

@ -0,0 +1,478 @@
/*
* Tests for switching between partitions: factory, OTAx, test.
*/
#include <esp_types.h>
#include <stdio.h>
#include "string.h"
#include "rom/spi_flash.h"
#include "rom/rtc.h"
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/xtensa_api.h"
#include "unity.h"
#include "bootloader_common.h"
#include "../include_bootloader/bootloader_flash.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_flash_partitions.h"
#include "esp_image_format.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
RTC_DATA_ATTR static int boot_count = 0;
static const char *TAG = "ota_test";
/* @brief Copies a current app to next partition using handle.
*
* @param[in] update_handle - Handle of API ota.
* @param[in] cur_app - Current app.
*/
static void copy_app_partition(esp_ota_handle_t update_handle, const esp_partition_t *curr_app)
{
const void *partition_bin = NULL;
spi_flash_mmap_handle_t data_map;
TEST_ESP_OK(esp_partition_mmap(curr_app, 0, curr_app->size, SPI_FLASH_MMAP_DATA, &partition_bin, &data_map));
TEST_ESP_OK(esp_ota_write(update_handle, (const void *)partition_bin, curr_app->size));
spi_flash_munmap(data_map);
}
#if defined(CONFIG_BOOTLOADER_FACTORY_RESET) || defined(CONFIG_BOOTLOADER_APP_TEST)
/* @brief Copies partition from source partition to destination partition.
*
* Partitions can be of any types and subtypes.
* @param[in] dst_partition - Destination partition
* @param[in] src_partition - Source partition
*/
static void copy_partition(const esp_partition_t *dst_partition, const esp_partition_t *src_partition)
{
const void *partition_bin = NULL;
spi_flash_mmap_handle_t data_map;
TEST_ESP_OK(esp_partition_mmap(src_partition, 0, src_partition->size, SPI_FLASH_MMAP_DATA, &partition_bin, &data_map));
TEST_ESP_OK(esp_partition_erase_range(dst_partition, 0, dst_partition->size));
TEST_ESP_OK(esp_partition_write(dst_partition, 0, (const void *)partition_bin, dst_partition->size));
spi_flash_munmap(data_map);
}
#endif
/* @brief Get the next partition of OTA for the update.
*
* @return The next partition of OTA(OTA0-15).
*/
static const esp_partition_t * get_next_update_partition(void)
{
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
TEST_ASSERT_NOT_EQUAL(NULL, update_partition);
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", update_partition->subtype, update_partition->address);
return update_partition;
}
/* @brief Copies a current app to next partition (OTA0-15) and then configure OTA data for a new boot partition.
*
* @param[in] cur_app_partition - Current app.
* @param[in] next_app_partition - Next app for boot.
*/
static void copy_current_app_to_next_part(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition)
{
esp_ota_get_next_update_partition(NULL);
TEST_ASSERT_NOT_EQUAL(NULL, next_app_partition);
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", next_app_partition->subtype, next_app_partition->address);
esp_ota_handle_t update_handle = 0;
TEST_ESP_OK(esp_ota_begin(next_app_partition, OTA_SIZE_UNKNOWN, &update_handle));
copy_app_partition(update_handle, cur_app_partition);
TEST_ESP_OK(esp_ota_end(update_handle));
TEST_ESP_OK(esp_ota_set_boot_partition(next_app_partition));
}
/* @brief Erase otadata partition
*/
static void erase_ota_data(void)
{
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
TEST_ASSERT_NOT_EQUAL(NULL, data_partition);
TEST_ESP_OK(esp_partition_erase_range(data_partition, 0, 2 * SPI_FLASH_SEC_SIZE));
}
/* @brief Reboots ESP using mode deep sleep. This mode guaranty that RTC_DATA_ATTR variables is not reset.
*/
static void reboot_as_deep_sleep(void)
{
esp_sleep_enable_timer_wakeup(2000);
esp_deep_sleep_start();
}
/* @brief Copies a current app to next partition (OTA0-15), after that ESP is rebooting and run this (the next) OTAx.
*/
static void copy_current_app_to_next_part_and_reboot()
{
const esp_partition_t *cur_app = esp_ota_get_running_partition();
copy_current_app_to_next_part(cur_app, get_next_update_partition());
reboot_as_deep_sleep();
}
/* @brief Get running app.
*
* @return The next partition of OTA(OTA0-15).
*/
static const esp_partition_t* get_running_firmware(void)
{
const esp_partition_t *configured = esp_ota_get_boot_partition();
const esp_partition_t *running = esp_ota_get_running_partition();
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
running->type, running->subtype, running->address);
ESP_LOGI(TAG, "Configured partition type %d subtype %d (offset 0x%08x)",
configured->type, configured->subtype, configured->address);
TEST_ASSERT_NOT_EQUAL(NULL, configured);
TEST_ASSERT_NOT_EQUAL(NULL, running);
if (running->subtype != ESP_PARTITION_SUBTYPE_APP_TEST) {
TEST_ASSERT_EQUAL_PTR(running, configured);
}
return running;
}
// type of a corrupt ota_data
typedef enum {
CORR_CRC_1_SECTOR_OTA_DATA = (1 << 0), /*!< Corrupt CRC only 1 sector of ota_data */
CORR_CRC_2_SECTOR_OTA_DATA = (1 << 1), /*!< Corrupt CRC only 2 sector of ota_data */
} corrupt_ota_data_t;
/* @brief Get two copies ota_data from otadata partition.
*
* @param[in] otadata_partition - otadata partition.
* @param[out] ota_data_0 - First copy from otadata_partition.
* @param[out] ota_data_1 - Second copy from otadata_partition.
*/
static void get_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data_0, esp_ota_select_entry_t *ota_data_1)
{
uint32_t offset = otadata_partition->address;
uint32_t size = otadata_partition->size;
if (offset != 0) {
const esp_ota_select_entry_t *ota_select_map;
ota_select_map = bootloader_mmap(offset, size);
TEST_ASSERT_NOT_EQUAL(NULL, ota_select_map);
memcpy(ota_data_0, ota_select_map, sizeof(esp_ota_select_entry_t));
memcpy(ota_data_1, (uint8_t *)ota_select_map + SPI_FLASH_SEC_SIZE, sizeof(esp_ota_select_entry_t));
bootloader_munmap(ota_select_map);
}
}
/* @brief Writes a ota_data into required sector of otadata_partition.
*
* @param[in] otadata_partition - Partition information otadata.
* @param[in] ota_data - otadata structure.
* @param[in] sec_id - Sector number 0 or 1.
*/
static void write_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data, int sec_id)
{
esp_partition_write(otadata_partition, SPI_FLASH_SEC_SIZE * sec_id, &ota_data[sec_id], sizeof(esp_ota_select_entry_t));
}
/* @brief Makes a corrupt of ota_data.
* @param[in] err - type error
*/
static void corrupt_ota_data(corrupt_ota_data_t err)
{
esp_ota_select_entry_t ota_data[2];
const esp_partition_t *otadata_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
TEST_ASSERT_NOT_EQUAL(NULL, otadata_partition);
get_ota_data(otadata_partition, &ota_data[0], &ota_data[1]);
if (err & CORR_CRC_1_SECTOR_OTA_DATA) {
ota_data[0].crc = 0;
}
if (err & CORR_CRC_2_SECTOR_OTA_DATA) {
ota_data[1].crc = 0;
}
TEST_ESP_OK(esp_partition_erase_range(otadata_partition, 0, otadata_partition->size));
write_ota_data(otadata_partition, &ota_data[0], 0);
write_ota_data(otadata_partition, &ota_data[1], 1);
}
#if defined(CONFIG_BOOTLOADER_FACTORY_RESET) || defined(CONFIG_BOOTLOADER_APP_TEST)
/* @brief Sets the pin number to output and sets output level as low. After reboot (deep sleep) this pin keep the same level.
*
* The output level of the pad will be force locked and can not be changed.
* Power down or call gpio_hold_dis will disable this function.
*
* @param[in] num_pin - Pin number
*/
static void set_output_pin(uint32_t num_pin)
{
TEST_ESP_OK(gpio_hold_dis(num_pin));
gpio_config_t io_conf;
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = (1ULL << num_pin);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
TEST_ESP_OK(gpio_config(&io_conf));
TEST_ESP_OK(gpio_set_level(num_pin, 0));
TEST_ESP_OK(gpio_hold_en(num_pin));
}
/* @brief Unset the pin number hold function.
*/
static void reset_output_pin(uint32_t num_pin)
{
TEST_ESP_OK(gpio_hold_dis(num_pin));
TEST_ESP_OK(gpio_reset_pin(num_pin));
}
#endif
/* @brief Checks and prepares the partition so that the factory app is launched after that.
*/
static void start_test(void)
{
ESP_LOGI(TAG, "boot count 1 - reset");
boot_count = 1;
erase_ota_data();
reboot_as_deep_sleep();
}
static void test_flow1(void)
{
boot_count++;
ESP_LOGI(TAG, "boot count %d", boot_count);
const esp_partition_t *cur_app = get_running_firmware();
switch (boot_count) {
case 2:
ESP_LOGI(TAG, "Factory");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
copy_current_app_to_next_part_and_reboot(cur_app);
break;
case 3:
ESP_LOGI(TAG, "OTA0");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
copy_current_app_to_next_part_and_reboot(cur_app);
break;
case 4:
ESP_LOGI(TAG, "OTA1");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_1, cur_app->subtype);
copy_current_app_to_next_part_and_reboot(cur_app);
break;
case 5:
ESP_LOGI(TAG, "OTA0");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
erase_ota_data();
break;
default:
erase_ota_data();
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
}
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
// 3 Stage: run OTA0 -> check it -> copy OTA0 to OTA1 -> reboot --//--
// 4 Stage: run OTA1 -> check it -> copy OTA1 to OTA0 -> reboot --//--
// 5 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, OTA0", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow1, test_flow1, test_flow1, test_flow1);
static void test_flow2(void)
{
boot_count++;
ESP_LOGI(TAG, "boot count %d", boot_count);
const esp_partition_t *cur_app = get_running_firmware();
switch (boot_count) {
case 2:
ESP_LOGI(TAG, "Factory");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
copy_current_app_to_next_part_and_reboot(cur_app);
break;
case 3:
ESP_LOGI(TAG, "OTA0");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
copy_current_app_to_next_part(cur_app, get_next_update_partition());
corrupt_ota_data(CORR_CRC_1_SECTOR_OTA_DATA);
reboot_as_deep_sleep();
break;
case 4:
ESP_LOGI(TAG, "Factory");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
erase_ota_data();
break;
default:
erase_ota_data();
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
}
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
// 3 Stage: run OTA0 -> check it -> corrupt ota data -> reboot --//--
// 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, corrupt ota_sec1, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow2, test_flow2, test_flow2);
static void test_flow3(void)
{
boot_count++;
ESP_LOGI(TAG, "boot count %d", boot_count);
const esp_partition_t *cur_app = get_running_firmware();
switch (boot_count) {
case 2:
ESP_LOGI(TAG, "Factory");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
copy_current_app_to_next_part_and_reboot(cur_app);
break;
case 3:
ESP_LOGI(TAG, "OTA0");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
copy_current_app_to_next_part_and_reboot(cur_app);
break;
case 4:
ESP_LOGI(TAG, "OTA1");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_1, cur_app->subtype);
copy_current_app_to_next_part(cur_app, get_next_update_partition());
corrupt_ota_data(CORR_CRC_2_SECTOR_OTA_DATA);
reboot_as_deep_sleep();
break;
case 5:
ESP_LOGI(TAG, "OTA0");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
erase_ota_data();
break;
default:
erase_ota_data();
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
}
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
// 3 Stage: run OTA0 -> check it -> copy OTA0 to OTA1 -> reboot --//--
// 3 Stage: run OTA1 -> check it -> corrupt ota sector2 -> reboot --//--
// 4 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, currupt ota_sec2, OTA0", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow3, test_flow3, test_flow3, test_flow3);
#ifdef CONFIG_BOOTLOADER_FACTORY_RESET
#define STORAGE_NAMESPACE "update_ota"
static void test_flow4(void)
{
boot_count++;
ESP_LOGI(TAG, "boot count %d", boot_count);
const esp_partition_t *cur_app = get_running_firmware();
nvs_handle handle = 0;
int boot_count_nvs = 0;
switch (boot_count) {
case 2:
ESP_LOGI(TAG, "Factory");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
TEST_ESP_OK(nvs_flash_erase());
TEST_ESP_OK(nvs_flash_init());
TEST_ESP_OK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle));
TEST_ESP_OK(nvs_set_i32(handle, "boot_count", boot_count));
TEST_ESP_OK(nvs_commit(handle));
nvs_close(handle);
nvs_flash_deinit();
copy_current_app_to_next_part_and_reboot(cur_app);
break;
case 3:
ESP_LOGI(TAG, "OTA0");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
TEST_ESP_OK(nvs_flash_init());
TEST_ESP_OK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle));
TEST_ESP_OK(nvs_get_i32(handle, "boot_count", &boot_count_nvs));
TEST_ASSERT_EQUAL(boot_count_nvs + 1, boot_count);
nvs_close(handle);
nvs_flash_deinit();
set_output_pin(CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET);
reboot_as_deep_sleep();
break;
case 4:
reset_output_pin(CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET);
ESP_LOGI(TAG, "Factory");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
int boot_count_nvs;
TEST_ESP_OK(nvs_flash_init());
TEST_ESP_OK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle));
TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, nvs_get_i32(handle, "boot_count", &boot_count_nvs));
nvs_close(handle);
nvs_flash_deinit();
erase_ota_data();
break;
default:
reset_output_pin(CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET);
erase_ota_data();
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
}
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
// 3 Stage: run OTA0 -> check it -> set_pin_factory_reset -> reboot --//--
// 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, sets pin_factory_reset, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow4, test_flow4, test_flow4);
#endif
#ifdef CONFIG_BOOTLOADER_APP_TEST
static void test_flow5(void)
{
boot_count++;
ESP_LOGI(TAG, "boot count %d", boot_count);
const esp_partition_t *cur_app = get_running_firmware();
switch (boot_count) {
case 2:
ESP_LOGI(TAG, "Factory");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
set_output_pin(CONFIG_BOOTLOADER_NUM_PIN_APP_TEST);
copy_partition(esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEST, NULL), cur_app);
esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
reboot_as_deep_sleep();
break;
case 3:
reset_output_pin(CONFIG_BOOTLOADER_NUM_PIN_APP_TEST);
ESP_LOGI(TAG, "Test");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_TEST, cur_app->subtype);
reboot_as_deep_sleep();
break;
case 4:
ESP_LOGI(TAG, "Factory");
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
erase_ota_data();
break;
default:
reset_output_pin(CONFIG_BOOTLOADER_NUM_PIN_APP_TEST);
erase_ota_data();
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
}
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
// 2 Stage: run factory -> check it -> copy factory to Test and set pin_test_app -> reboot --//--
// 3 Stage: run test -> check it -> reset pin_test_app -> reboot --//--
// 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
TEST_CASE_MULTIPLE_STAGES("Switching between factory, test, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow5, test_flow5, test_flow5);
#endif

View File

@ -49,14 +49,14 @@ ifndef CONFIG_SECURE_BOOT_ENABLED
# If secure boot disabled, bootloader flashing is integrated
# with 'make flash' and no warnings are printed.
bootloader: $(BOOTLOADER_BIN)
bootloader: $(BOOTLOADER_BIN) | check_python_dependencies
@echo $(SEPARATOR)
@echo "Bootloader built. Default flash command is:"
@echo "$(ESPTOOLPY_WRITE_FLASH) $(BOOTLOADER_OFFSET) $^"
ESPTOOL_ALL_FLASH_ARGS += $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)
bootloader-flash: $(BOOTLOADER_BIN) $(call prereq_if_explicit,erase_flash)
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
@ -67,7 +67,7 @@ else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
# The flashing command is deliberately printed without an auto-reset
# step, so the device doesn't immediately reset to flash itself.
bootloader: $(BOOTLOADER_BIN)
bootloader: $(BOOTLOADER_BIN) | check_python_dependencies
@echo $(SEPARATOR)
@echo "Bootloader built. One-time flash command is:"
@echo "$(subst hard_reset,no_reset,$(ESPTOOLPY_WRITE_FLASH)) $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)"
@ -82,7 +82,7 @@ BOOTLOADER_DIGEST_BIN := $(BOOTLOADER_BUILD_DIR)/bootloader-reflash-digest.bin
SECURE_BOOTLOADER_KEY := $(BOOTLOADER_BUILD_DIR)/secure-bootloader-key.bin
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY)
$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY) | check_python_dependencies
$(ESPSECUREPY) digest_private_key -k $< $@
else
$(SECURE_BOOTLOADER_KEY):
@ -105,7 +105,7 @@ bootloader: $(BOOTLOADER_DIGEST_BIN)
@echo "* After first boot, only re-flashes of this kind (with same key) will be accepted."
@echo "* Not recommended to re-use the same secure boot keyfile on multiple production devices."
$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY)
$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY) | check_python_dependencies
@echo "DIGEST $(notdir $@)"
$(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOTLOADER_KEY) -o $@ $<

View File

@ -101,4 +101,14 @@ esp_err_t esp_flash_encrypt_check_and_update(void);
*/
esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length);
/** @brief Write protect FLASH_CRYPT_CNT
*
* Intended to be called as a part of boot process if flash encryption
* is enabled but secure boot is not used. This should protect against
* serial re-flashing of an unauthorised code in absence of secure boot.
*
* @return
*/
void esp_flash_write_protect_crypt_cnt();
#endif

View File

@ -29,7 +29,7 @@ void bootloader_clock_configure()
uart_tx_wait_idle(0);
/* Set CPU to 80MHz. Keep other clocks unmodified. */
rtc_cpu_freq_t cpu_freq = RTC_CPU_FREQ_80M;
int cpu_freq_mhz = 80;
/* On ESP32 rev 0, switching to 80MHz if clock was previously set to
* 240 MHz may cause the chip to lock up (see section 3.5 of the errata
@ -39,12 +39,12 @@ void bootloader_clock_configure()
uint32_t chip_ver_reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
if ((chip_ver_reg & EFUSE_RD_CHIP_VER_REV1_M) == 0 &&
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240) {
cpu_freq = RTC_CPU_FREQ_240M;
cpu_freq_mhz = 240;
}
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
clk_cfg.cpu_freq = cpu_freq;
clk_cfg.cpu_freq_mhz = cpu_freq_mhz;
clk_cfg.slow_freq = rtc_clk_slow_freq_get();
clk_cfg.fast_freq = rtc_clk_fast_freq_get();
rtc_clk_init(clk_cfg);

View File

@ -337,3 +337,13 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
return err;
}
void esp_flash_write_protect_crypt_cnt()
{
uint32_t efuse_blk0 = REG_READ(EFUSE_BLK0_RDATA0_REG);
bool flash_crypt_wr_dis = efuse_blk0 & EFUSE_WR_DIS_FLASH_CRYPT_CNT;
if(!flash_crypt_wr_dis) {
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_FLASH_CRYPT_CNT);
esp_efuse_burn_new_values();
}
}

View File

@ -6,6 +6,68 @@ config BT_ENABLED
help
Select this option to enable Bluetooth and show the submenu with Bluetooth configuration choices.
menu "Bluetooth controller"
visible if BT_ENABLED
choice BTDM_CONTROLLER_MODE
prompt "Bluetooth controller mode (BR/EDR/BLE/DUALMODE)"
depends on BT_ENABLED
help
Specify the bluetooth controller mode (BR/EDR, BLE or dual mode).
config BTDM_CONTROLLER_MODE_BLE_ONLY
bool "BLE Only"
config BTDM_CONTROLLER_MODE_BR_EDR_ONLY
bool "BR/EDR Only"
config BTDM_CONTROLLER_MODE_BTDM
bool "Bluetooth Dual Mode"
endchoice
config BTDM_CONTROLLER_BLE_MAX_CONN
int "BLE Max Connections"
depends on BTDM_CONTROLLER_MODE_BLE_ONLY || BTDM_CONTROLLER_MODE_BTDM
default 3
range 1 9
help
BLE maximum connections of bluetooth controller.
Each connection uses 1KB static DRAM whenever the BT controller is enabled.
config BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN
int "BR/EDR ACL Max Connections"
depends on BTDM_CONTROLLER_MODE_BR_EDR_ONLY || BTDM_CONTROLLER_MODE_BTDM
default 2
range 1 7
help
BR/EDR ACL maximum connections of bluetooth controller.
Each connection uses 1.2KB static DRAM whenever the BT controller is enabled.
config BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN
int "BR/EDR Sync(SCO/eSCO) Max Connections"
depends on BTDM_CONTROLLER_MODE_BR_EDR_ONLY || BTDM_CONTROLLER_MODE_BTDM
default 0
range 0 3
help
BR/EDR Synchronize maximum connections of bluetooth controller.
Each connection uses 2KB static DRAM whenever the BT controller is enabled.
config BTDM_CONTROLLER_BLE_MAX_CONN_EFF
int
default BTDM_CONTROLLER_BLE_MAX_CONN if BTDM_CONTROLLER_MODE_BLE_ONLY || BTDM_CONTROLLER_MODE_BTDM
default 0
config BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF
int
default BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN if BTDM_CONTROLLER_MODE_BR_EDR_ONLY || BTDM_CONTROLLER_MODE_BTDM
default 0
config BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF
int
default BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN if BTDM_CONTROLLER_MODE_BR_EDR_ONLY || BTDM_CONTROLLER_MODE_BTDM
default 0
choice BTDM_CONTROLLER_PINNED_TO_CORE_CHOICE
prompt "The cpu core which bluetooth controller run"
depends on BT_ENABLED && !FREERTOS_UNICORE
@ -104,6 +166,42 @@ config BTDM_LPCLK_SEL_EXT_32K_XTAL
depends on ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
endchoice
endmenu
config BLE_SCAN_DUPLICATE
bool "BLE Scan Duplicate Options"
depends on (BTDM_CONTROLLER_MODE_BTDM || BTDM_CONTROLLER_MODE_BLE_ONLY)
default y
help
This select enables parameters setting of BLE scan duplicate.
config DUPLICATE_SCAN_CACHE_SIZE
int "Maximum number of devices in scan duplicate filter"
depends on BLE_SCAN_DUPLICATE
range 10 200
default 20
help
Maximum number of devices which can be recorded in scan duplicate filter.
When the maximum amount of device in the filter is reached, the cache will be refreshed.
config BLE_MESH_SCAN_DUPLICATE_EN
bool "Special duplicate scan mechanism for BLE Mesh scan"
depends on BLE_SCAN_DUPLICATE
default n
help
This enables the BLE scan duplicate for special BLE Mesh scan.
config MESH_DUPLICATE_SCAN_CACHE_SIZE
int "Maximum number of Mesh adv packets in scan duplicate filter"
depends on BLE_MESH_SCAN_DUPLICATE_EN
range 10 200
default 50
help
Maximum number of adv packets which can be recorded in duplicate scan cache for BLE Mesh.
When the maximum amount of device in the filter is reached, the cache will be refreshed.
endmenu
menuconfig BLUEDROID_ENABLED
@ -213,28 +311,28 @@ endchoice
config GATTS_ENABLE
bool "Include GATT server module(GATTS)"
depends on BLUEDROID_ENABLED
depends on BLUEDROID_ENABLED && (BTDM_CONTROLLER_MODE_BTDM || BTDM_CONTROLLER_MODE_BLE_ONLY)
default y
help
This option can be disabled when the app work only on gatt client mode
config GATTC_ENABLE
bool "Include GATT client module(GATTC)"
depends on BLUEDROID_ENABLED
depends on BLUEDROID_ENABLED && (BTDM_CONTROLLER_MODE_BTDM || BTDM_CONTROLLER_MODE_BLE_ONLY)
default y
help
This option can be close when the app work only on gatt server mode
config GATTC_CACHE_NVS_FLASH
bool "Save gattc cache data to nvs flash"
depends on GATTC_ENABLE
depends on GATTC_ENABLE && (BTDM_CONTROLLER_MODE_BTDM || BTDM_CONTROLLER_MODE_BLE_ONLY)
default n
help
This select can save gattc cache data to nvs flash
config BLE_SMP_ENABLE
bool "Include BLE security module(SMP)"
depends on BLUEDROID_ENABLED
depends on BLUEDROID_ENABLED && (BTDM_CONTROLLER_MODE_BTDM || BTDM_CONTROLLER_MODE_BLE_ONLY)
default y
help
This option can be close when the app not used the ble security connect.
@ -1018,38 +1116,6 @@ config BLE_HOST_QUEUE_CONGESTION_CHECK
handling adv packets is slow, it will cause the controller memory to run out. if enabled, adv packets will be
lost when host queue is congested.
config BLE_SCAN_DUPLICATE
bool "BLE Scan Duplicate Options"
depends on BLUEDROID_ENABLED
default y
help
This select enables parameters setting of BLE scan duplicate.
config DUPLICATE_SCAN_CACHE_SIZE
int "Maximum number of devices in scan duplicate filter"
depends on BLE_SCAN_DUPLICATE
range 10 1000
default 50
help
Maximum number of devices which can be recorded in scan duplicate filter.
When the maximum amount of device in the filter is reached, the cache will be refreshed.
config BLE_MESH_SCAN_DUPLICATE_EN
bool "Special duplicate scan mechanism for BLE Mesh scan"
depends on BLE_SCAN_DUPLICATE
default n
help
This enables the BLE scan duplicate for special BLE Mesh scan.
config MESH_DUPLICATE_SCAN_CACHE_SIZE
int "Maximum number of Mesh adv packets in scan duplicate filter"
depends on BLE_MESH_SCAN_DUPLICATE_EN
range 10 1000
default 100
help
Maximum number of adv packets which can be recorded in duplicate scan cache for BLE Mesh.
When the maximum amount of device in the filter is reached, the cache will be refreshed.
config SMP_ENABLE
bool
depends on BLUEDROID_ENABLED
@ -1058,7 +1124,7 @@ config SMP_ENABLE
# Memory reserved at start of DRAM for Bluetooth stack
config BT_RESERVE_DRAM
hex
default 0x10000 if BT_ENABLED
default 0xdb5c if BT_ENABLED
default 0
endmenu

View File

@ -1291,7 +1291,9 @@ void bta_gattc_get_db_with_opration(UINT16 conn_id,
tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (p_clcb == NULL) {
return NULL;
*count = 0;
*char_db = NULL;
return;
}
tBTA_GATTC_SERV *p_srcb = p_clcb->p_srcb;
@ -1671,7 +1673,8 @@ void bta_gattc_get_db_size_with_type_handle(UINT16 conn_id, bt_gatt_db_attribute
tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (p_clcb == NULL) {
return NULL;
*count = 0;
return;
}
tBTA_GATTC_SERV *p_srcb = p_clcb->p_srcb;

View File

@ -578,13 +578,14 @@ void bta_gattc_clear_notif_registration(tBTA_GATTC_SERV *p_srcb, UINT16 conn_id,
for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++) {
if (p_clrcb->notif_reg[i].in_use &&
!bdcmp(p_clrcb->notif_reg[i].remote_bda, remote_bda))
{
/* It's enough to get service or characteristic handle, as
* clear boundaries are always around service.
*/
handle = p_clrcb->notif_reg[i].handle;
if (handle >= start_handle && handle <= end_handle)
memset(&p_clrcb->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
}
}
}
} else {

View File

@ -702,6 +702,10 @@ void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
APPL_TRACE_ERROR("%s, malloc failed", __func__);
}
(*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
if (cb_data.req_data.value != NULL) {
osi_free(cb_data.req_data.value);
cb_data.req_data.value = NULL;
}
}
} else {
APPL_TRACE_ERROR("Not an registered servce attribute ID: 0x%04x",

View File

@ -209,10 +209,7 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
blufi_env.frag_size = p_data->req_data.p_data->mtu - BLUFI_MTU_RESERVED_SIZE;
break;
case BTA_GATTS_CONF_EVT:
BLUFI_TRACE_DEBUG("CONIRM EVT\n");
if (p_data && p_data->req_data.value){
osi_free(p_data->req_data.value);
}
BLUFI_TRACE_DEBUG("CONFIRM EVT\n");
/* Nothing */
break;
case BTA_GATTS_CREATE_EVT:

View File

@ -586,7 +586,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
OI_STATUS status;
int num_sbc_frames = p_msg->num_frames_to_be_processed;
UINT32 sbc_frame_len = p_msg->len - 1;
availPcmBytes = 2 * sizeof(pcmData);
availPcmBytes = sizeof(pcmData);
/* XXX: Check if the below check is correct, we are checking for peer to be sink when we are sink */
if (btc_av_get_peer_sep() == AVDT_TSEP_SNK || (btc_aa_snk_cb.rx_flush)) {
@ -617,7 +617,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
p_msg->len = sbc_frame_len + 1;
}
btc_a2d_data_cb_to_app((uint8_t *)pcmData, (2 * sizeof(pcmData) - availPcmBytes));
btc_a2d_data_cb_to_app((uint8_t *)pcmData, (sizeof(pcmData) - availPcmBytes));
}
/*******************************************************************************

View File

@ -530,9 +530,6 @@ static void btc_gatts_cb_param_copy_free(btc_msg_t *msg, tBTA_GATTS *p_data)
}
break;
case BTA_GATTS_CONF_EVT:
if (p_data && p_data->req_data.value){
osi_free(p_data->req_data.value);
}
break;
default:
break;

View File

@ -112,8 +112,9 @@ static bool hal_open(const hci_hal_callbacks_t *upper_callbacks)
xTaskCreatePinnedToCore(hci_hal_h4_rx_handler, HCI_H4_TASK_NAME, HCI_H4_TASK_STACK_SIZE, NULL, HCI_H4_TASK_PRIO, &xHciH4TaskHandle, HCI_H4_TASK_PINNED_TO_CORE);
//register vhci host cb
esp_vhci_host_register_callback(&vhci_host_cb);
if (esp_vhci_host_register_callback(&vhci_host_cb) != ESP_OK) {
return false;
}
return true;
}

View File

@ -336,7 +336,8 @@ static int get_config_size_from_flash(nvs_handle fp)
assert(fp != 0);
esp_err_t err;
char *keyname = osi_calloc(sizeof(CONFIG_KEY) + 1);
const size_t keyname_bufsz = sizeof(CONFIG_KEY) + 5 + 1; // including log10(sizeof(i))
char *keyname = osi_calloc(keyname_bufsz);
if (!keyname){
OSI_TRACE_ERROR("%s, malloc error\n", __func__);
return 0;
@ -344,7 +345,7 @@ static int get_config_size_from_flash(nvs_handle fp)
size_t length = CONFIG_FILE_DEFAULE_LENGTH;
size_t total_length = 0;
uint16_t i = 0;
snprintf(keyname, sizeof(CONFIG_KEY) + 1, "%s%d", CONFIG_KEY, 0);
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, 0);
err = nvs_get_blob(fp, keyname, NULL, &length);
if (err == ESP_ERR_NVS_NOT_FOUND) {
osi_free(keyname);
@ -358,7 +359,7 @@ static int get_config_size_from_flash(nvs_handle fp)
total_length += length;
while (length == CONFIG_FILE_MAX_SIZE) {
length = CONFIG_FILE_DEFAULE_LENGTH;
snprintf(keyname, sizeof(CONFIG_KEY) + 1, "%s%d", CONFIG_KEY, ++i);
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, ++i);
err = nvs_get_blob(fp, keyname, NULL, &length);
if (err == ESP_ERR_NVS_NOT_FOUND) {
@ -385,7 +386,8 @@ bool config_save(const config_t *config, const char *filename)
int err_code = 0;
nvs_handle fp;
char *line = osi_calloc(1024);
char *keyname = osi_calloc(sizeof(CONFIG_KEY) + 1);
const size_t keyname_bufsz = sizeof(CONFIG_KEY) + 5 + 1; // including log10(sizeof(i))
char *keyname = osi_calloc(keyname_bufsz);
int config_size = get_config_size(config);
char *buf = osi_calloc(config_size + 100);
if (!line || !buf || !keyname) {
@ -430,7 +432,7 @@ bool config_save(const config_t *config, const char *filename)
}
buf[w_cnt_total] = '\0';
if (w_cnt_total < CONFIG_FILE_MAX_SIZE) {
snprintf(keyname, sizeof(CONFIG_KEY)+1, "%s%d", CONFIG_KEY, 0);
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, 0);
err = nvs_set_blob(fp, keyname, buf, w_cnt_total);
if (err != ESP_OK) {
nvs_close(fp);
@ -441,7 +443,7 @@ bool config_save(const config_t *config, const char *filename)
uint count = (w_cnt_total / CONFIG_FILE_MAX_SIZE);
for (int i = 0; i <= count; i++)
{
snprintf(keyname, sizeof(CONFIG_KEY)+1, "%s%d", CONFIG_KEY, i);
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, i);
if (i == count) {
err = nvs_set_blob(fp, keyname, buf + i*CONFIG_FILE_MAX_SIZE, w_cnt_total - i*CONFIG_FILE_MAX_SIZE);
OSI_TRACE_DEBUG("save keyname = %s, i = %d, %d\n", keyname, i, w_cnt_total - i*CONFIG_FILE_MAX_SIZE);
@ -518,14 +520,15 @@ static void config_parse(nvs_handle fp, config_t *config)
size_t total_length = 0;
char *line = osi_calloc(1024);
char *section = osi_calloc(1024);
char *keyname = osi_calloc(sizeof(CONFIG_KEY) + 1);
const size_t keyname_bufsz = sizeof(CONFIG_KEY) + 5 + 1; // including log10(sizeof(i))
char *keyname = osi_calloc(keyname_bufsz);
int buf_size = get_config_size_from_flash(fp);
char *buf = osi_calloc(buf_size + 100);
if (!line || !section || !buf || !keyname) {
err_code |= 0x01;
goto error;
}
snprintf(keyname, sizeof(CONFIG_KEY)+1, "%s%d", CONFIG_KEY, 0);
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, 0);
err = nvs_get_blob(fp, keyname, buf, &length);
if (err == ESP_ERR_NVS_NOT_FOUND) {
goto error;
@ -537,7 +540,7 @@ static void config_parse(nvs_handle fp, config_t *config)
total_length += length;
while (length == CONFIG_FILE_MAX_SIZE) {
length = CONFIG_FILE_DEFAULE_LENGTH;
snprintf(keyname, sizeof(CONFIG_KEY) + 1, "%s%d", CONFIG_KEY, ++i);
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, ++i);
err = nvs_get_blob(fp, keyname, buf + CONFIG_FILE_MAX_SIZE * i, &length);
if (err == ESP_ERR_NVS_NOT_FOUND) {

View File

@ -99,13 +99,13 @@ list_node_t *list_back_node(const list_t *list) {
}
bool list_insert_after(list_t *list, list_node_t *prev_node, void *data) {
assert(list != NULL);
assert(prev_node != NULL);
assert(data != NULL);
assert(list != NULL);
assert(prev_node != NULL);
assert(data != NULL);
list_node_t *node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t));
if (!node)
return false;
list_node_t *node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t));
if (!node)
return false;
node->next = prev_node->next;
node->data = data;

View File

@ -352,8 +352,8 @@ UINT8 A2D_SetTraceLevel (UINT8 new_level)
******************************************************************************/
UINT8 A2D_BitsSet(UINT8 num)
{
UINT8 count;
BOOLEAN res;
UINT8 count;
UINT8 res;
if (num == 0) {
res = A2D_SET_ZERO_BIT;
} else {

View File

@ -331,8 +331,8 @@ void btm_ble_scan_pf_cmpl_cback(tBTM_VSC_CMPL *p_params)
break;
}
BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback: calling the cback: %d", cb_evt);
switch (cb_evt) {
BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback: calling the cback: %d", cb_evt);
case BTM_BLE_FILT_CFG:
if (NULL != p_scan_cfg_cback) {
p_scan_cfg_cback(action, cond_type, num_avail, status, ref_value);

View File

@ -1439,7 +1439,8 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, max_scan_interval) &&
BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, max_scan_window) &&
(scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS)) {
(scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS) &&
(scan_duplicate_filter < BTM_BLE_SCAN_DUPLICATE_MAX)) {
p_cb->scan_type = scan_mode;
p_cb->scan_interval = scan_interval;
p_cb->scan_window = scan_window;
@ -2637,7 +2638,7 @@ static void btm_ble_parse_adv_data(tBTM_INQ_INFO *p_info, UINT8 *p_data,
** Returns void
**
*******************************************************************************/
void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
void btm_ble_cache_adv_data(BD_ADDR bda, tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
{
tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
UINT8 *p_cache;
@ -2649,6 +2650,15 @@ void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, U
memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
p_cur->adv_data_len = 0;
p_cur->scan_rsp_len = 0;
}
//Clear the adv cache if the addresses are not equal
if(memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) != 0) {
p_le_inq_cb->adv_len = 0;
memcpy(p_le_inq_cb->adv_addr, bda, BD_ADDR_LEN);
memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
p_cur->adv_data_len = 0;
p_cur->scan_rsp_len = 0;
}
if (data_len > 0) {
@ -2878,7 +2888,7 @@ static void btm_ble_appearance_to_cod(UINT16 appearance, UINT8 *dev_class)
** Returns void
**
*******************************************************************************/
BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
BOOLEAN btm_ble_update_inq_result(BD_ADDR bda, tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
{
BOOLEAN to_report = TRUE;
tBTM_INQ_RESULTS *p_cur = &p_i->inq_info.results;
@ -2896,7 +2906,7 @@ BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_t
BTM_TRACE_WARNING("EIR data too long %d. discard", data_len);
return FALSE;
}
btm_ble_cache_adv_data(p_cur, data_len, p, evt_type);
btm_ble_cache_adv_data(bda, p_cur, data_len, p, evt_type);
p1 = (p + data_len);
STREAM_TO_UINT8 (rssi, p1);
@ -3120,6 +3130,71 @@ void btm_ble_process_adv_pkt (UINT8 *p_data)
}
}
/*******************************************************************************
**
** Function btm_ble_process_last_adv_pkt
**
** Description This function is called to report last adv packet
**
** Parameters
**
** Returns void
**
*******************************************************************************/
static void btm_ble_process_last_adv_pkt(void)
{
UINT8 result = 0;
UINT8 null_bda[6] = {0};
tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
tBTM_INQ_RESULTS_CB *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
tBTM_INQ_RESULTS_CB *p_scan_results_cb = btm_cb.ble_ctr_cb.p_scan_results_cb;
tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
tINQ_DB_ENT *p_i = btm_inq_db_find (p_le_inq_cb->adv_addr);
if(memcmp(null_bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) == 0) {
return;
}
if(p_i == NULL) {
BTM_TRACE_DEBUG("no last adv");
return;
}
if ((result = btm_ble_is_discoverable(p_le_inq_cb->adv_addr, p_i->inq_info.results.ble_evt_type, NULL)) == 0) {
BTM_TRACE_WARNING("%s device is no longer discoverable so discarding advertising packet pkt",
__func__);
return;
}
/* background connection in selective connection mode */
if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
//do nothing
} else {
if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
(p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
(p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
(p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
}
}
/*******************************************************************************
**
** Function btm_ble_process_adv_pkt_cont
@ -3144,6 +3219,13 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
BOOLEAN update = TRUE;
UINT8 result = 0;
//if scan duplicate is enabled, the adv packet without scan response is allowed to report to higgher layer
if(p_le_inq_cb->scan_duplicate_filter == BTM_BLE_SCAN_DUPLICATE_ENABLE) {
if(memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) != 0) {
btm_ble_process_last_adv_pkt();
}
}
p_i = btm_inq_db_find (bda);
/* Check if this address has already been processed for this inquiry */
@ -3172,7 +3254,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
p_inq->inq_cmpl_info.num_resp++;
}
/* update the LE device information in inquiry database */
if (!btm_ble_update_inq_result(p_i, addr_type, evt_type, p)) {
if (!btm_ble_update_inq_result(bda, p_i, addr_type, evt_type, p)) {
return;
}
@ -3216,12 +3298,24 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
} else {
if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
(p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
(p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
(p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
}
}

View File

@ -162,7 +162,7 @@ typedef struct {
UINT8 adv_len;
UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX];
BD_ADDR adv_addr;
/* inquiry BD addr database */
UINT8 num_bd_entries;
UINT8 max_bd_entries;

View File

@ -242,23 +242,6 @@ void btu_task_thread_handler(void *arg)
case SIG_BTU_ONESHOT_ALARM: {
TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)e.par;
btu_general_alarm_process(p_tle);
switch (p_tle->event) {
#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
case BTU_TTYPE_BLE_RANDOM_ADDR:
btm_ble_timeout(p_tle);
break;
#endif
case BTU_TTYPE_USER_FUNC: {
tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
(*p_uf)(p_tle);
break;
}
default:
// FAIL
HCI_TRACE_ERROR("Received unexpected oneshot timer event:0x%x\n", p_tle->event);
break;
}
break;
}
case SIG_BTU_L2CAP_ALARM:

View File

@ -1038,7 +1038,10 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) {
sent = TRUE;
p_cmd->to_send = FALSE;
p_cmd->p_cmd = NULL;
if(p_cmd->p_cmd) {
osi_free(p_cmd->p_cmd);
p_cmd->p_cmd = NULL;
}
/* dequeue the request if is write command or sign write */
if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE) {

View File

@ -2258,6 +2258,7 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport)
GATT_TRACE_DEBUG ("exit gatt_cleanup_upon_disc ");
BTM_Recovery_Pre_State();
}
gatt_delete_dev_from_srv_chg_clt_list(bda);
}
/*******************************************************************************
**

View File

@ -582,6 +582,12 @@ typedef struct {
tBTM_BLE_REF_VALUE ref_value;
} tBTM_BLE_BATCH_SCAN_CB;
/// Ble scan duplicate type
enum {
BTM_BLE_SCAN_DUPLICATE_DISABLE = 0x0, /*!< the Link Layer should generate advertising reports to the host for each packet received */
BTM_BLE_SCAN_DUPLICATE_ENABLE = 0x1, /*!< the Link Layer should filter out duplicate advertising reports to the Host */
BTM_BLE_SCAN_DUPLICATE_MAX = 0x2, /*!< 0x02 0xFF, Reserved for future use */
};
/* filter selection bit index */
#define BTM_BLE_PF_ADDR_FILTER 0
#define BTM_BLE_PF_SRVC_DATA 1

View File

@ -41,8 +41,8 @@ void p_256_init_curve(UINT32 keyLength)
ec->p[1] = 0xFFFFFFFF;
ec->p[0] = 0xFFFFFFFF;
memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256);
memset(ec->a, 0, KEY_LENGTH_DWORDS_P256);
memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256 * sizeof(ec->omega[0]));
memset(ec->a, 0, KEY_LENGTH_DWORDS_P256 * sizeof(ec->a[0]));
ec->a_minus3 = TRUE;

View File

@ -105,7 +105,10 @@ static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN conne
if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0) {
return;
}
if(!connected && &p_cb->rsp_timer_ent) {
//free timer
btu_free_timer(&p_cb->rsp_timer_ent);
}
if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s\n",
__FUNCTION__,

View File

@ -41,11 +41,16 @@
#include "driver/periph_ctrl.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/soc_memory_layout.h"
#include "esp_clk.h"
#if CONFIG_BT_ENABLED
/* Macro definition
************************************************************************
*/
#define BTDM_LOG_TAG "BTDM_INIT"
#define BTDM_INIT_PERIOD (5000) /* ms */
@ -56,65 +61,20 @@
#define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<2)
#define BTDM_CFG_SCAN_DUPLICATE_OPTIONS (1<<3)
#define BTDM_CFG_SEND_ADV_RESERVED_SIZE (1<<4)
/* Other reserved for future */
/* not for user call, so don't put to include file */
extern void btdm_osi_funcs_register(void *osi_funcs);
extern int btdm_controller_init(uint32_t config_mask, esp_bt_controller_config_t *config_opts);
extern void btdm_controller_deinit(void);
extern int btdm_controller_enable(esp_bt_mode_t mode);
extern void btdm_controller_disable(void);
extern uint8_t btdm_controller_get_mode(void);
extern const char *btdm_controller_get_compile_version(void);
extern void btdm_rf_bb_init(void);
extern void btdm_controller_enable_sleep(bool enable);
/* Sleep mode */
#define BTDM_MODEM_SLEEP_MODE_NONE (0)
#define BTDM_MODEM_SLEEP_MODE_ORIG (1)
#define BTDM_MODEM_SLEEP_MODE_EVED (2)
extern void btdm_controller_set_sleep_mode(uint8_t mode);
extern uint8_t btdm_controller_get_sleep_mode(void);
extern bool btdm_power_state_active(void);
extern void btdm_wakeup_request(void);
/* Low Power Clock Selection */
#define BTDM_LPCLK_SEL_XTAL (0)
#define BTDM_LPCLK_SEL_XTAL32K (1)
#define BTDM_LPCLK_SEL_RTC_SLOW (2)
#define BTDM_LPCLK_SEL_8M (3)
extern bool btdm_lpclk_select_src(uint32_t sel);
extern bool btdm_lpclk_set_div(uint32_t div);
/* Sleep duration */
#define BTDM_MIN_SLEEP_DURATION (20)
/* VHCI function interface */
typedef struct vhci_host_callback {
void (*notify_host_send_available)(void); /*!< callback used to notify that the host can send packet to controller */
int (*notify_host_recv)(uint8_t *data, uint16_t len); /*!< callback used to notify that the controller has a packet to send to the host*/
} vhci_host_callback_t;
extern bool API_vhci_host_check_send_available(void);
extern void API_vhci_host_send_packet(uint8_t *data, uint16_t len);
extern void API_vhci_host_register_callback(const vhci_host_callback_t *callback);
extern int ble_txpwr_set(int power_type, int power_level);
extern int ble_txpwr_get(int power_type);
extern int bredr_txpwr_set(int min_power_level, int max_power_level);
extern int bredr_txpwr_get(int *min_power_level, int *max_power_level);
extern void bredr_sco_datapath_set(uint8_t data_path);
extern char _bss_start_btdm;
extern char _bss_end_btdm;
extern uint32_t _bt_bss_start;
extern uint32_t _bt_bss_end;
extern uint32_t _btdm_bss_start;
extern uint32_t _btdm_bss_end;
extern uint32_t _bt_data_start;
extern uint32_t _bt_data_end;
extern uint32_t _btdm_data_start;
extern uint32_t _btdm_data_end;
extern char _data_start_btdm;
extern char _data_end_btdm;
extern uint32_t _data_start_btdm_rom;
extern uint32_t _data_end_btdm_rom;
#define BT_DEBUG(...)
#define BT_API_CALL_CHECK(info, api_call, ret) \
@ -127,45 +87,43 @@ do{\
} while(0)
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff
#define OSI_VERSION 0x00010001
#define OSI_MAGIC_VALUE 0xFADEBEAD
/* SPIRAM Configuration */
#if CONFIG_SPIRAM_USE_MALLOC
#define BTDM_MAX_QUEUE_NUM (5)
#endif
/* Types definition
************************************************************************
*/
/* VHCI function interface */
typedef struct vhci_host_callback {
void (*notify_host_send_available)(void); /*!< callback used to notify that the host can send packet to controller */
int (*notify_host_recv)(uint8_t *data, uint16_t len); /*!< callback used to notify that the controller has a packet to send to the host*/
} vhci_host_callback_t;
/* Dram region */
typedef struct {
esp_bt_mode_t mode;
intptr_t start;
intptr_t end;
} btdm_dram_available_region_t;
/* the mode column will be modified by release function to indicate the available region */
static btdm_dram_available_region_t btdm_dram_available_region[] = {
//following is .data
{ESP_BT_MODE_BTDM, 0x3ffae6e0, 0x3ffaff10},
//following is memory which HW will use
{ESP_BT_MODE_BTDM, 0x3ffb0000, 0x3ffb09a8},
{ESP_BT_MODE_BLE, 0x3ffb09a8, 0x3ffb1ddc},
{ESP_BT_MODE_BTDM, 0x3ffb1ddc, 0x3ffb2730},
{ESP_BT_MODE_CLASSIC_BT, 0x3ffb2730, 0x3ffb8000},
//following is .bss
{ESP_BT_MODE_BTDM, 0x3ffb8000, 0x3ffbbb28},
{ESP_BT_MODE_CLASSIC_BT, 0x3ffbbb28, 0x3ffbdb28},
{ESP_BT_MODE_BTDM, 0x3ffbdb28, 0x3ffc0000},
};
/* Reserve the full memory region used by Bluetooth Controller,
some may be released later at runtime. */
SOC_RESERVE_MEMORY_REGION(0x3ffb0000, 0x3ffc0000, bt_hardware_shared_mem);
SOC_RESERVE_MEMORY_REGION(0x3ffae6e0, 0x3ffaff10, rom_bt_data);
/* PSRAM configuration */
#if CONFIG_SPIRAM_USE_MALLOC
typedef struct {
QueueHandle_t handle;
void *storage;
void *buffer;
} btdm_queue_item_t;
#define BTDM_MAX_QUEUE_NUM (5)
static btdm_queue_item_t btdm_queue_table[BTDM_MAX_QUEUE_NUM];
SemaphoreHandle_t btdm_queue_table_mux = NULL;
#endif /* #if CONFIG_SPIRAM_USE_MALLOC */
#endif
/* OSI function */
struct osi_funcs_t {
uint32_t _version;
xt_handler (*_set_isr)(int n, xt_handler f, void *arg);
void (*_ints_on)(unsigned int mask);
void (*_interrupt_disable)(void);
@ -193,6 +151,7 @@ struct osi_funcs_t {
bool (* _is_in_isr)(void);
int (* _cause_sw_intr_to_core)(int core_id, int intr_no);
void *(* _malloc)(uint32_t size);
void *(* _malloc_internal)(uint32_t size);
void (* _free)(void *p);
int32_t (* _read_efuse_mac)(uint8_t mac[6]);
void (* _srand)(unsigned int seed);
@ -202,9 +161,176 @@ struct osi_funcs_t {
bool (* _btdm_sleep_check_duration)(uint32_t *slot_cnt);
void (* _btdm_sleep_enter)(void);
void (* _btdm_sleep_exit)(void); /* called from ISR */
uint32_t _magic;
};
/* External functions or values
************************************************************************
*/
/* not for user call, so don't put to include file */
/* OSI */
extern int btdm_osi_funcs_register(void *osi_funcs);
/* Initialise and De-initialise */
extern int btdm_controller_init(uint32_t config_mask, esp_bt_controller_config_t *config_opts);
extern void btdm_controller_deinit(void);
extern int btdm_controller_enable(esp_bt_mode_t mode);
extern void btdm_controller_disable(void);
extern uint8_t btdm_controller_get_mode(void);
extern const char *btdm_controller_get_compile_version(void);
extern void btdm_rf_bb_init(void);
/* Sleep */
extern void btdm_controller_enable_sleep(bool enable);
extern void btdm_controller_set_sleep_mode(uint8_t mode);
extern uint8_t btdm_controller_get_sleep_mode(void);
extern bool btdm_power_state_active(void);
extern void btdm_wakeup_request(void);
/* Low Power Clock */
extern bool btdm_lpclk_select_src(uint32_t sel);
extern bool btdm_lpclk_set_div(uint32_t div);
/* VHCI */
extern bool API_vhci_host_check_send_available(void);
extern void API_vhci_host_send_packet(uint8_t *data, uint16_t len);
extern int API_vhci_host_register_callback(const vhci_host_callback_t *callback);
/* TX power */
extern int ble_txpwr_set(int power_type, int power_level);
extern int ble_txpwr_get(int power_type);
extern int bredr_txpwr_set(int min_power_level, int max_power_level);
extern int bredr_txpwr_get(int *min_power_level, int *max_power_level);
extern void bredr_sco_datapath_set(uint8_t data_path);
extern char _bss_start_btdm;
extern char _bss_end_btdm;
extern char _data_start_btdm;
extern char _data_end_btdm;
extern uint32_t _data_start_btdm_rom;
extern uint32_t _data_end_btdm_rom;
extern uint32_t _bt_bss_start;
extern uint32_t _bt_bss_end;
extern uint32_t _btdm_bss_start;
extern uint32_t _btdm_bss_end;
extern uint32_t _bt_data_start;
extern uint32_t _bt_data_end;
extern uint32_t _btdm_data_start;
extern uint32_t _btdm_data_end;
/* Local Function Declare
*********************************************************************
*/
#if CONFIG_SPIRAM_USE_MALLOC
static bool IRAM_ATTR btdm_queue_generic_register(const btdm_queue_item_t *queue);
static bool IRAM_ATTR btdm_queue_generic_deregister(btdm_queue_item_t *queue);
#endif /* CONFIG_SPIRAM_USE_MALLOC */
static void IRAM_ATTR interrupt_disable(void);
static void IRAM_ATTR interrupt_restore(void);
static void IRAM_ATTR task_yield_from_isr(void);
static void *IRAM_ATTR semphr_create_wrapper(uint32_t max, uint32_t init);
static void IRAM_ATTR semphr_delete_wrapper(void *semphr);
static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw);
static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw);
static int32_t IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time_ms);
static int32_t IRAM_ATTR semphr_give_wrapper(void *semphr);
static void *IRAM_ATTR mutex_create_wrapper(void);
static void IRAM_ATTR mutex_delete_wrapper(void *mutex);
static int32_t IRAM_ATTR mutex_lock_wrapper(void *mutex);
static int32_t IRAM_ATTR mutex_unlock_wrapper(void *mutex);
static void *IRAM_ATTR queue_create_wrapper(uint32_t queue_len, uint32_t item_size);
static void IRAM_ATTR queue_delete_wrapper(void *queue);
static int32_t IRAM_ATTR queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw);
static int32_t IRAM_ATTR queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw);
static int32_t IRAM_ATTR task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
static void IRAM_ATTR task_delete_wrapper(void *task_handle);
static bool IRAM_ATTR is_in_isr_wrapper(void);
static void IRAM_ATTR cause_sw_intr(void *arg);
static int IRAM_ATTR cause_sw_intr_to_core_wrapper(int core_id, int intr_no);
static void * IRAM_ATTR malloc_internal_wrapper(size_t size);
static int32_t IRAM_ATTR read_mac_wrapper(uint8_t mac[6]);
static void IRAM_ATTR srand_wrapper(unsigned int seed);
static int IRAM_ATTR rand_wrapper(void);
static uint32_t IRAM_ATTR btdm_lpcycles_2_us(uint32_t cycles);
static uint32_t IRAM_ATTR btdm_us_2_lpcycles(uint32_t us);
static bool IRAM_ATTR btdm_sleep_check_duration(uint32_t *slot_cnt);
static void IRAM_ATTR btdm_sleep_enter_wrapper(void);
static void IRAM_ATTR btdm_sleep_exit_wrapper(void);
/* Local variable definition
***************************************************************************
*/
/* OSI funcs */
static const struct osi_funcs_t osi_funcs_ro = {
._version = OSI_VERSION,
._set_isr = xt_set_interrupt_handler,
._ints_on = xt_ints_on,
._interrupt_disable = interrupt_disable,
._interrupt_restore = interrupt_restore,
._task_yield = vPortYield,
._task_yield_from_isr = task_yield_from_isr,
._semphr_create = semphr_create_wrapper,
._semphr_delete = semphr_delete_wrapper,
._semphr_take_from_isr = semphr_take_from_isr_wrapper,
._semphr_give_from_isr = semphr_give_from_isr_wrapper,
._semphr_take = semphr_take_wrapper,
._semphr_give = semphr_give_wrapper,
._mutex_create = mutex_create_wrapper,
._mutex_delete = mutex_delete_wrapper,
._mutex_lock = mutex_lock_wrapper,
._mutex_unlock = mutex_unlock_wrapper,
._queue_create = queue_create_wrapper,
._queue_delete = queue_delete_wrapper,
._queue_send = queue_send_wrapper,
._queue_send_from_isr = queue_send_from_isr_wrapper,
._queue_recv = queue_recv_wrapper,
._queue_recv_from_isr = queue_recv_from_isr_wrapper,
._task_create = task_create_wrapper,
._task_delete = task_delete_wrapper,
._is_in_isr = is_in_isr_wrapper,
._cause_sw_intr_to_core = cause_sw_intr_to_core_wrapper,
._malloc = malloc,
._malloc_internal = malloc_internal_wrapper,
._free = free,
._read_efuse_mac = read_mac_wrapper,
._srand = srand_wrapper,
._rand = rand_wrapper,
._btdm_lpcycles_2_us = btdm_lpcycles_2_us,
._btdm_us_2_lpcycles = btdm_us_2_lpcycles,
._btdm_sleep_check_duration = btdm_sleep_check_duration,
._btdm_sleep_enter = btdm_sleep_enter_wrapper,
._btdm_sleep_exit = btdm_sleep_exit_wrapper,
._magic = OSI_MAGIC_VALUE,
};
/* the mode column will be modified by release function to indicate the available region */
static btdm_dram_available_region_t btdm_dram_available_region[] = {
//following is .data
{ESP_BT_MODE_BTDM, SOC_MEM_BT_DATA_START, SOC_MEM_BT_DATA_END },
//following is memory which HW will use
{ESP_BT_MODE_BTDM, SOC_MEM_BT_EM_BTDM0_START, SOC_MEM_BT_EM_BTDM0_END },
{ESP_BT_MODE_BLE, SOC_MEM_BT_EM_BLE_START, SOC_MEM_BT_EM_BLE_END },
{ESP_BT_MODE_BTDM, SOC_MEM_BT_EM_BTDM1_START, SOC_MEM_BT_EM_BTDM1_END },
{ESP_BT_MODE_CLASSIC_BT, SOC_MEM_BT_EM_BREDR_START, SOC_MEM_BT_EM_BREDR_REAL_END},
//following is .bss
{ESP_BT_MODE_BTDM, SOC_MEM_BT_BSS_START, SOC_MEM_BT_BSS_END },
{ESP_BT_MODE_BTDM, SOC_MEM_BT_MISC_START, SOC_MEM_BT_MISC_END },
};
/* Reserve the full memory region used by Bluetooth Controller,
* some may be released later at runtime. */
SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_EM_START, SOC_MEM_BT_EM_BREDR_REAL_END, rom_bt_em);
SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_BSS_START, SOC_MEM_BT_BSS_END, rom_bt_bss);
SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_MISC_START, SOC_MEM_BT_MISC_END, rom_bt_misc);
SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_DATA_START, SOC_MEM_BT_DATA_END, rom_bt_data);
static struct osi_funcs_t *osi_funcs_p;
#if CONFIG_SPIRAM_USE_MALLOC
static btdm_queue_item_t btdm_queue_table[BTDM_MAX_QUEUE_NUM];
SemaphoreHandle_t btdm_queue_table_mux = NULL;
#endif /* #if CONFIG_SPIRAM_USE_MALLOC */
/* Static variable declare */
static bool btdm_bb_init_flag = false;
static esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
@ -220,7 +346,7 @@ static esp_pm_lock_handle_t s_pm_lock;
#endif
#if CONFIG_SPIRAM_USE_MALLOC
bool IRAM_ATTR btdm_queue_generic_register(const btdm_queue_item_t *queue)
static bool IRAM_ATTR btdm_queue_generic_register(const btdm_queue_item_t *queue)
{
if (!btdm_queue_table_mux || !queue) {
return NULL;
@ -241,7 +367,7 @@ bool IRAM_ATTR btdm_queue_generic_register(const btdm_queue_item_t *queue)
return ret;
}
bool IRAM_ATTR btdm_queue_generic_deregister(btdm_queue_item_t *queue)
static bool IRAM_ATTR btdm_queue_generic_deregister(btdm_queue_item_t *queue)
{
if (!btdm_queue_table_mux || !queue) {
return false;
@ -579,6 +705,11 @@ static int IRAM_ATTR cause_sw_intr_to_core_wrapper(int core_id, int intr_no)
return err;
}
static void * IRAM_ATTR malloc_internal_wrapper(size_t size)
{
return heap_caps_malloc(size, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
}
static int32_t IRAM_ATTR read_mac_wrapper(uint8_t mac[6])
{
return esp_read_mac(mac, ESP_MAC_BT);
@ -650,45 +781,6 @@ static void IRAM_ATTR btdm_sleep_exit_wrapper(void)
}
}
static struct osi_funcs_t osi_funcs = {
._set_isr = xt_set_interrupt_handler,
._ints_on = xt_ints_on,
._interrupt_disable = interrupt_disable,
._interrupt_restore = interrupt_restore,
._task_yield = vPortYield,
._task_yield_from_isr = task_yield_from_isr,
._semphr_create = semphr_create_wrapper,
._semphr_delete = semphr_delete_wrapper,
._semphr_take_from_isr = semphr_take_from_isr_wrapper,
._semphr_give_from_isr = semphr_give_from_isr_wrapper,
._semphr_take = semphr_take_wrapper,
._semphr_give = semphr_give_wrapper,
._mutex_create = mutex_create_wrapper,
._mutex_delete = mutex_delete_wrapper,
._mutex_lock = mutex_lock_wrapper,
._mutex_unlock = mutex_unlock_wrapper,
._queue_create = queue_create_wrapper,
._queue_delete = queue_delete_wrapper,
._queue_send = queue_send_wrapper,
._queue_send_from_isr = queue_send_from_isr_wrapper,
._queue_recv = queue_recv_wrapper,
._queue_recv_from_isr = queue_recv_from_isr_wrapper,
._task_create = task_create_wrapper,
._task_delete = task_delete_wrapper,
._is_in_isr = is_in_isr_wrapper,
._cause_sw_intr_to_core = cause_sw_intr_to_core_wrapper,
._malloc = malloc,
._free = free,
._read_efuse_mac = read_mac_wrapper,
._srand = srand_wrapper,
._rand = rand_wrapper,
._btdm_lpcycles_2_us = btdm_lpcycles_2_us,
._btdm_us_2_lpcycles = btdm_us_2_lpcycles,
._btdm_sleep_check_duration = btdm_sleep_check_duration,
._btdm_sleep_enter = btdm_sleep_enter_wrapper,
._btdm_sleep_exit = btdm_sleep_exit_wrapper,
};
bool esp_vhci_host_check_send_available(void)
{
return API_vhci_host_check_send_available();
@ -702,19 +794,15 @@ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
API_vhci_host_send_packet(data, len);
}
void esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
{
API_vhci_host_register_callback((const vhci_host_callback_t *)callback);
return API_vhci_host_register_callback((const vhci_host_callback_t *)callback) == 0 ? ESP_OK : ESP_FAIL;
}
static uint32_t btdm_config_mask_load(void)
{
uint32_t mask = 0x0;
if (btdm_dram_available_region[0].mode == ESP_BT_MODE_BLE) {
mask |= BTDM_CFG_BT_DATA_RELEASE;
}
#if CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4
mask |= BTDM_CFG_HCI_UART;
#endif
@ -730,10 +818,11 @@ static uint32_t btdm_config_mask_load(void)
static void btdm_controller_mem_init(void)
{
/* initialise .bss, .data and .etc section */
/* 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);
//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);
@ -796,12 +885,16 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode)
if (mode == ESP_BT_MODE_BTDM) {
mem_start = (intptr_t)&_btdm_bss_start;
mem_end = (intptr_t)&_btdm_bss_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));
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));
}
mem_start = (intptr_t)&_btdm_data_start;
mem_end = (intptr_t)&_btdm_data_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));
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));
}
}
return ESP_OK;
}
@ -819,12 +912,16 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode)
if (mode == ESP_BT_MODE_BTDM) {
mem_start = (intptr_t)&_bt_bss_start;
mem_end = (intptr_t)&_bt_bss_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));
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));
}
mem_start = (intptr_t)&_bt_data_start;
mem_end = (intptr_t)&_bt_data_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));
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));
}
}
return ESP_OK;
}
@ -834,6 +931,16 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
BaseType_t ret;
uint32_t btdm_cfg_mask = 0;
osi_funcs_p = (struct osi_funcs_t *)malloc_internal_wrapper(sizeof(struct osi_funcs_t));
if (osi_funcs_p == NULL) {
return ESP_ERR_NO_MEM;
}
memcpy(osi_funcs_p, &osi_funcs_ro, sizeof(struct osi_funcs_t));
if (btdm_osi_funcs_register(osi_funcs_p) != 0) {
return ESP_ERR_INVALID_ARG;
}
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) {
return ESP_ERR_INVALID_STATE;
}
@ -852,6 +959,16 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
return ESP_ERR_INVALID_ARG;
}
//overwrite some parameters
cfg->bt_max_sync_conn = CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF;
cfg->magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL;
if (((cfg->mode & ESP_BT_MODE_BLE) && (cfg->ble_max_conn <= 0 || cfg->ble_max_conn > BTDM_CONTROLLER_BLE_MAX_CONN_LIMIT))
|| ((cfg->mode & ESP_BT_MODE_CLASSIC_BT) && (cfg->bt_max_acl_conn <= 0 || cfg->bt_max_acl_conn > BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_LIMIT))
|| ((cfg->mode & ESP_BT_MODE_CLASSIC_BT) && (cfg->bt_max_sync_conn > BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_LIMIT))) {
return ESP_ERR_INVALID_ARG;
}
#ifdef CONFIG_PM_ENABLE
esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock);
if (err != ESP_OK) {
@ -873,8 +990,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM);
#endif
btdm_osi_funcs_register(&osi_funcs);
btdm_controller_mem_init();
periph_module_enable(PERIPH_BT_MODULE);
@ -936,6 +1051,9 @@ esp_err_t esp_bt_controller_deinit(void)
memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM);
#endif
free(osi_funcs_p);
osi_funcs_p = NULL;
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
btdm_lpcycle_us = 0;
@ -956,8 +1074,8 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
return ESP_ERR_INVALID_STATE;
}
//check the mode is available mode
if (mode & ~btdm_dram_available_region[0].mode) {
//As the history reason, mode should be equal to the mode which set in esp_bt_controller_init()
if (mode != btdm_controller_get_mode()) {
return ESP_ERR_INVALID_ARG;
}

View File

@ -25,83 +25,7 @@
extern "C" {
#endif
/**
* @brief Controller config options, depend on config mask.
* Config mask indicate which functions enabled, this means
* some options or parameters of some functions enabled by config mask.
*/
typedef struct {
uint16_t controller_task_stack_size; /*!< Bluetooth controller task stack size */
uint8_t controller_task_prio; /*!< Bluetooth controller task priority */
uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */
uint32_t hci_uart_baudrate; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
uint8_t scan_duplicate_mode; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
uint16_t normal_adv_size; /*!< Normal adv size for scan duplicate */
uint16_t mesh_adv_size; /*!< Mesh adv size for scan duplicate */
uint16_t send_adv_reserved_size; /*!< Controller minimum memory value */
uint32_t controller_debug_flag; /*!< Controller debug log flag */
} esp_bt_controller_config_t;
#ifdef CONFIG_BT_ENABLED
/* While scanning, if the free memory value in controller is less than SCAN_SEND_ADV_RESERVED_SIZE,
the adv packet will be discarded until the memory is restored. */
#define SCAN_SEND_ADV_RESERVED_SIZE 1000
/* enable controller log debug when adv lost */
#define CONTROLLER_ADV_LOST_DEBUG_BIT (0<<0)
#ifdef CONFIG_BT_HCI_UART_NO
#define BT_HCI_UART_NO_DEFAULT CONFIG_BT_HCI_UART_NO
#else
#define BT_HCI_UART_NO_DEFAULT 1
#endif /* BT_HCI_UART_NO_DEFAULT */
#ifdef CONFIG_BT_HCI_UART_BAUDRATE
#define BT_HCI_UART_BAUDRATE_DEFAULT CONFIG_BT_HCI_UART_BAUDRATE
#else
#define BT_HCI_UART_BAUDRATE_DEFAULT 921600
#endif /* BT_HCI_UART_BAUDRATE_DEFAULT */
/* normal adv cache size */
#ifdef CONFIG_DUPLICATE_SCAN_CACHE_SIZE
#define NORMAL_SCAN_DUPLICATE_CACHE_SIZE CONFIG_DUPLICATE_SCAN_CACHE_SIZE
#else
#define NORMAL_SCAN_DUPLICATE_CACHE_SIZE 20
#endif
#ifndef CONFIG_BLE_MESH_SCAN_DUPLICATE_EN
#define CONFIG_BLE_MESH_SCAN_DUPLICATE_EN FALSE
#endif
#define SCAN_DUPLICATE_MODE_NORMAL_ADV_ONLY 0
#define SCAN_DUPLICATE_MODE_NORMAL_ADV_MESH_ADV 1
#if CONFIG_BLE_MESH_SCAN_DUPLICATE_EN
#define SCAN_DUPLICATE_MODE SCAN_DUPLICATE_MODE_NORMAL_ADV_MESH_ADV
#ifdef CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE
#define MESH_DUPLICATE_SCAN_CACHE_SIZE CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE
#else
#define MESH_DUPLICATE_SCAN_CACHE_SIZE 50
#endif
#else
#define SCAN_DUPLICATE_MODE SCAN_DUPLICATE_MODE_NORMAL_ADV_ONLY
#define MESH_DUPLICATE_SCAN_CACHE_SIZE 0
#endif
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \
.controller_task_stack_size = ESP_TASK_BT_CONTROLLER_STACK, \
.controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.hci_uart_no = BT_HCI_UART_NO_DEFAULT, \
.hci_uart_baudrate = BT_HCI_UART_BAUDRATE_DEFAULT, \
.scan_duplicate_mode = SCAN_DUPLICATE_MODE, \
.normal_adv_size = NORMAL_SCAN_DUPLICATE_CACHE_SIZE, \
.mesh_adv_size = MESH_DUPLICATE_SCAN_CACHE_SIZE, \
.send_adv_reserved_size = SCAN_SEND_ADV_RESERVED_SIZE, \
.controller_debug_flag = CONTROLLER_ADV_LOST_DEBUG_BIT, \
};
#else
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() {0}; _Static_assert(0, "please enable bluetooth in menuconfig to use bt.h");
#endif
#define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x5A5AA5A5
/**
* @brief Bluetooth mode for controller enable/disable
@ -113,6 +37,114 @@ typedef enum {
ESP_BT_MODE_BTDM = 0x03, /*!< Run dual mode */
} esp_bt_mode_t;
#ifdef CONFIG_BT_ENABLED
/* While scanning, if the free memory value in controller is less than SCAN_SEND_ADV_RESERVED_SIZE,
the adv packet will be discarded until the memory is restored. */
#define SCAN_SEND_ADV_RESERVED_SIZE 1000
/* enable controller log debug when adv lost */
#define CONTROLLER_ADV_LOST_DEBUG_BIT (0<<0)
#ifdef CONFIG_BT_HCI_UART_NO
#define BT_HCI_UART_NO_DEFAULT CONFIG_BT_HCI_UART_NO
#else
#define BT_HCI_UART_NO_DEFAULT 1
#endif /* BT_HCI_UART_NO_DEFAULT */
#ifdef CONFIG_BT_HCI_UART_BAUDRATE
#define BT_HCI_UART_BAUDRATE_DEFAULT CONFIG_BT_HCI_UART_BAUDRATE
#else
#define BT_HCI_UART_BAUDRATE_DEFAULT 921600
#endif /* BT_HCI_UART_BAUDRATE_DEFAULT */
/* normal adv cache size */
#ifdef CONFIG_DUPLICATE_SCAN_CACHE_SIZE
#define NORMAL_SCAN_DUPLICATE_CACHE_SIZE CONFIG_DUPLICATE_SCAN_CACHE_SIZE
#else
#define NORMAL_SCAN_DUPLICATE_CACHE_SIZE 20
#endif
#ifndef CONFIG_BLE_MESH_SCAN_DUPLICATE_EN
#define CONFIG_BLE_MESH_SCAN_DUPLICATE_EN FALSE
#endif
#define SCAN_DUPLICATE_MODE_NORMAL_ADV_ONLY 0
#define SCAN_DUPLICATE_MODE_NORMAL_ADV_MESH_ADV 1
#if CONFIG_BLE_MESH_SCAN_DUPLICATE_EN
#define SCAN_DUPLICATE_MODE SCAN_DUPLICATE_MODE_NORMAL_ADV_MESH_ADV
#ifdef CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE
#define MESH_DUPLICATE_SCAN_CACHE_SIZE CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE
#else
#define MESH_DUPLICATE_SCAN_CACHE_SIZE 50
#endif
#else
#define SCAN_DUPLICATE_MODE SCAN_DUPLICATE_MODE_NORMAL_ADV_ONLY
#define MESH_DUPLICATE_SCAN_CACHE_SIZE 0
#endif
#if defined(CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY)
#define BTDM_CONTROLLER_MODE_EFF ESP_BT_MODE_BLE
#elif defined(CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY)
#define BTDM_CONTROLLER_MODE_EFF ESP_BT_MODE_CLASSIC_BT
#else
#define BTDM_CONTROLLER_MODE_EFF ESP_BT_MODE_BTDM
#endif
#define BTDM_CONTROLLER_BLE_MAX_CONN_LIMIT 9 //Maximum BLE connection limitation
#define BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_LIMIT 7 //Maximum ACL connection limitation
#define BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_LIMIT 3 //Maximum SCO/eSCO connection limitation
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \
.controller_task_stack_size = ESP_TASK_BT_CONTROLLER_STACK, \
.controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.hci_uart_no = BT_HCI_UART_NO_DEFAULT, \
.hci_uart_baudrate = BT_HCI_UART_BAUDRATE_DEFAULT, \
.scan_duplicate_mode = SCAN_DUPLICATE_MODE, \
.normal_adv_size = NORMAL_SCAN_DUPLICATE_CACHE_SIZE, \
.mesh_adv_size = MESH_DUPLICATE_SCAN_CACHE_SIZE, \
.send_adv_reserved_size = SCAN_SEND_ADV_RESERVED_SIZE, \
.controller_debug_flag = CONTROLLER_ADV_LOST_DEBUG_BIT, \
.mode = BTDM_CONTROLLER_MODE_EFF, \
.ble_max_conn = CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF, \
.bt_max_acl_conn = CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF, \
.bt_max_sync_conn = CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF, \
.magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL, \
};
#else
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() {0}; _Static_assert(0, "please enable bluetooth in menuconfig to use bt.h");
#endif
/**
* @brief Controller config options, depend on config mask.
* Config mask indicate which functions enabled, this means
* some options or parameters of some functions enabled by config mask.
*/
typedef struct {
/*
* Following parameters can be configured runtime, when call esp_bt_controller_init()
*/
uint16_t controller_task_stack_size; /*!< Bluetooth controller task stack size */
uint8_t controller_task_prio; /*!< Bluetooth controller task priority */
uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */
uint32_t hci_uart_baudrate; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
uint8_t scan_duplicate_mode; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
uint16_t normal_adv_size; /*!< Normal adv size for scan duplicate */
uint16_t mesh_adv_size; /*!< Mesh adv size for scan duplicate */
uint16_t send_adv_reserved_size; /*!< Controller minimum memory value */
uint32_t controller_debug_flag; /*!< Controller debug log flag */
uint8_t mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */
uint8_t ble_max_conn; /*!< BLE maximum connection numbers */
uint8_t bt_max_acl_conn; /*!< BR/EDR maximum ACL connection numbers */
/*
* Following parameters can not be configured runtime when call esp_bt_controller_init()
* 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 */
uint32_t magic; /*!< Magic number */
} esp_bt_controller_config_t;
/**
* @brief Bluetooth controller enable/disable/initialised/de-initialised status
*/
@ -123,7 +155,6 @@ typedef enum {
ESP_BT_CONTROLLER_STATUS_NUM,
} esp_bt_controller_status_t;
/**
* @brief BLE tx power type
* ESP_BLE_PWR_TYPE_CONN_HDL0-8: for each connection, and only be set after connection completed.
@ -231,10 +262,11 @@ esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_l
esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path);
/**
* @brief Initialize BT controller to allocate task and other resource.
* @param cfg: Initial configuration of BT controller.
* This function should be called only once, before any other BT functions are called.
* @return ESP_OK - success, other - failed
* @brief Initialize BT controller to allocate task and other resource.
* This function should be called only once, before any other BT functions are called.
* @param cfg: Initial configuration of BT controller. Different from previous version, there's a mode and some
* connection configuration in "cfg" to configure controller work mode and allocate the resource which is needed.
* @return ESP_OK - success, other - failed
*/
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg);
@ -252,7 +284,8 @@ esp_err_t esp_bt_controller_deinit(void);
* Due to a known issue, you cannot call esp_bt_controller_enable() a second time
* to change the controller mode dynamically. To change controller mode, call
* esp_bt_controller_disable() and then call esp_bt_controller_enable() with the new mode.
* @param mode : the mode(BLE/BT/BTDM) to enable.
* @param mode : the mode(BLE/BT/BTDM) to enable. For compatible of API, retain this argument. This mode must be
* equal as the mode in "cfg" of esp_bt_controller_init().
* @return ESP_OK - success, other - failed
*/
esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode);
@ -294,8 +327,9 @@ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len);
* register the vhci referece callback, the call back
* struct defined by vhci_host_callback structure.
* @param callback esp_vhci_host_callback type variable
* @return ESP_OK - success, ESP_FAIL - failed
*/
void esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback);
esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback);
/** @brief esp_bt_controller_mem_release
* release the controller memory as per the mode

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

View File

@ -1,5 +1,5 @@
#
#Component Makefile
#
ifdef CONFIG_BT_ENABLED
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
else
COMPONENT_CONFIG_ONLY := 1
endif

View File

@ -6,8 +6,8 @@ config ADC_FORCE_XPD_FSM
bool "Use the FSM to control ADC power"
default n
help
ADC power can be controlled by the FSM instead of software. This allows the ADC to
be shut off when it is not working leading to lower power consumption. However
ADC power can be controlled by the FSM instead of software. This allows the ADC to
be shut off when it is not working leading to lower power consumption. However
using the FSM control ADC power will increase the noise of ADC.
config ADC2_DISABLE_DAC
@ -20,7 +20,7 @@ config ADC2_DISABLE_DAC
endmenu # ADC Configuration
menu "SPI master configuration"
menu "SPI configuration"
config SPI_MASTER_IN_IRAM
bool "Place transmitting functions of SPI master into IRAM"
@ -44,6 +44,26 @@ config SPI_MASTER_ISR_IN_IRAM
Place the SPI master ISR in to IRAM to avoid possibly cache miss, or
being disabled during flash writing access.
endmenu # SPI Master Configuration
config SPI_SLAVE_IN_IRAM
bool "Place transmitting functions of SPI slave into IRAM"
default n
select SPI_SLAVE_ISR_IN_IRAM
help
Normally only the ISR of SPI slave is placed in the IRAM, so that it
can work without the flash when interrupt is triggered.
For other functions, there's some possibility that the flash cache
miss when running inside and out of SPI functions, which may increase
the interval of SPI transactions.
Enable this to put ``queue_trans``, ``get_trans_result`` and
``transmit`` functions into the IRAM to avoid possible cache miss.
config SPI_SLAVE_ISR_IN_IRAM
bool "Place SPI slave ISR function into IRAM"
default y
help
Place the SPI slave ISR in to IRAM to avoid possibly cache miss, or
being disabled during flash writing access.
endmenu # SPI Configuration
endmenu # Driver configurations

View File

@ -330,7 +330,7 @@ void spicommon_cs_free_io(int cs_gpio_num)
}
//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to.
void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
void IRAM_ATTR spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
{
int n = 0;
while (len) {

View File

@ -177,7 +177,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
spihost[host]->dma_chan=dma_chan;
if (dma_chan == 0) {
spihost[host]->max_transfer_sz = 32;
spihost[host]->max_transfer_sz = 64;
} else {
//See how many dma descriptors we need and allocate them
int dma_desc_ct=(bus_config->max_transfer_sz+SPI_MAX_DMA_LEN-1)/SPI_MAX_DMA_LEN;
@ -213,6 +213,10 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
//Reset timing
spihost[host]->hw->ctrl2.val=0;
//master use all 64 bytes of the buffer
spihost[host]->hw->user.usr_miso_highpart=0;
spihost[host]->hw->user.usr_mosi_highpart=0;
//Disable unneeded ints
spihost[host]->hw->slave.rd_buf_done=0;
spihost[host]->hw->slave.wr_buf_done=0;
@ -607,6 +611,8 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
host->hw->dma_in_link.start=0;
host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
host->hw->dma_conf.out_data_burst_en=1;
host->hw->dma_conf.indscr_burst_en=1;
host->hw->dma_conf.outdscr_burst_en=1;
//Set up QIO/DIO if needed
host->hw->ctrl.val &= ~(SPI_FREAD_DUAL|SPI_FREAD_QUAD|SPI_FREAD_DIO|SPI_FREAD_QIO);
host->hw->user.val &= ~(SPI_FWRITE_DUAL|SPI_FWRITE_QUAD|SPI_FWRITE_DIO|SPI_FWRITE_QIO);
@ -633,7 +639,6 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
//Fill DMA descriptors
int extra_dummy=0;
if (trans_buf->buffer_to_rcv) {
host->hw->user.usr_miso_highpart=0;
if (host->dma_chan == 0) {
//No need to setup anything; we'll copy the result out of the work registers directly later.
} else {
@ -662,16 +667,13 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
//Use memcpy to get around alignment issues for txdata
uint32_t word;
memcpy(&word, &trans_buf->buffer_to_send[x/32], 4);
host->hw->data_buf[(x/32)+8]=word;
host->hw->data_buf[(x/32)]=word;
}
host->hw->user.usr_mosi_highpart=1;
} else {
spicommon_dmaworkaround_transfer_active(host->dma_chan); //mark channel as active
spicommon_setup_dma_desc_links(host->dmadesc_tx, (trans->length+7)/8, (uint8_t*)trans_buf->buffer_to_send, false);
host->hw->user.usr_mosi_highpart=0;
host->hw->dma_out_link.addr=(int)(&host->dmadesc_tx[0]) & 0xFFFFF;
host->hw->dma_out_link.start=1;
host->hw->user.usr_mosi_highpart=0;
}
}

View File

@ -47,6 +47,18 @@ static const char *SPI_TAG = "spi_slave";
#define VALID_HOST(x) (x>SPI_HOST && x<=VSPI_HOST)
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
#define SPI_SLAVE_ISR_ATTR IRAM_ATTR
#else
#define SPI_SLAVE_ISR_ATTR
#endif
#ifdef CONFIG_SPI_SLAVE_IN_IRAM
#define SPI_SLAVE_ATTR IRAM_ATTR
#else
#define SPI_SLAVE_ATTR
#endif
typedef struct {
spi_slave_interface_config_t cfg;
intr_handle_t intr;
@ -79,7 +91,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
spi_chan_claimed=spicommon_periph_claim(host);
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
if ( dma_chan != 0 ) {
dma_chan_claimed=spicommon_dma_chan_claim(dma_chan);
if ( !dma_chan_claimed ) {
@ -138,7 +150,11 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
goto cleanup;
}
err = esp_intr_alloc(spicommon_irqsource_for_host(host), ESP_INTR_FLAG_INTRDISABLED, spi_intr, (void *)spihost[host], &spihost[host]->intr);
int flags = ESP_INTR_FLAG_INTRDISABLED;
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
flags |= ESP_INTR_FLAG_IRAM;
#endif
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr);
if (err != ESP_OK) {
ret = err;
goto cleanup;
@ -250,14 +266,14 @@ esp_err_t spi_slave_free(spi_host_device_t host)
}
esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)
esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)
{
BaseType_t r;
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL || esp_ptr_dma_capable(trans_desc->rx_buffer),
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL || esp_ptr_dma_capable(trans_desc->rx_buffer),
"rxdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
@ -268,7 +284,7 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact
}
esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait)
esp_err_t SPI_SLAVE_ATTR spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait)
{
BaseType_t r;
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
@ -279,7 +295,7 @@ esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transacti
}
esp_err_t spi_slave_transmit(spi_host_device_t host, spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)
esp_err_t SPI_SLAVE_ATTR spi_slave_transmit(spi_host_device_t host, spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)
{
esp_err_t ret;
spi_slave_transaction_t *ret_trans;
@ -316,7 +332,7 @@ static void dumpll(lldesc_t *ll)
}
#endif
static void IRAM_ATTR spi_slave_restart_after_dmareset(void *arg)
static void SPI_SLAVE_ISR_ATTR spi_slave_restart_after_dmareset(void *arg)
{
spi_slave_t *host = (spi_slave_t *)arg;
esp_intr_enable(host->intr);
@ -325,7 +341,7 @@ static void IRAM_ATTR spi_slave_restart_after_dmareset(void *arg)
//This is run in interrupt context and apart from initialization and destruction, this is the only code
//touching the host (=spihost[x]) variable. The rest of the data arrives in queues. That is why there are
//no muxes in this code.
static void IRAM_ATTR spi_intr(void *arg)
static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
{
BaseType_t r;
BaseType_t do_yield = pdFALSE;
@ -342,7 +358,7 @@ static void IRAM_ATTR spi_intr(void *arg)
if (host->cur_trans) {
//when data of cur_trans->length are all sent, the slv_rdata_bit
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
//the length sent.
host->cur_trans->trans_len = host->hw->slv_rd_bit.slv_rdata_bit;
if ( host->cur_trans->trans_len == host->cur_trans->length - 1 ) {

View File

@ -88,7 +88,7 @@ static void fill_item_end(rmt_item32_t* item)
/**
* @brief Check whether duration is around target_us
*/
inline bool check_in_range(int duration_ticks, int target_us, int margin_us)
static inline bool check_in_range(int duration_ticks, int target_us, int margin_us)
{
if(( ITEM_DURATION(duration_ticks) < (target_us + margin_us))
&& ( ITEM_DURATION(duration_ticks) > (target_us - margin_us))) {

View File

@ -234,6 +234,10 @@ TEST_CASE("SPI Master test", "[spi]")
success &= spi_test(handle, 4); //aligned
success &= spi_test(handle, 16); //small
success &= spi_test(handle, 21); //small, unaligned
success &= spi_test(handle, 32); //small
success &= spi_test(handle, 47); //small, unaligned
success &= spi_test(handle, 63); //small
success &= spi_test(handle, 64); //small, unaligned
destroy_spi_bus(handle);
@ -575,7 +579,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]")
ESP_LOGI(TAG, "iram: %p, dram: %p", data_iram, data_dram);
ESP_LOGI(TAG, "drom: %p, malloc: %p", data_drom, data_malloc);
memset(trans, 0, 6*sizeof(spi_transaction_t));
memset(trans, 0, sizeof(trans));
trans[0].length = 320*8,
trans[0].tx_buffer = data_iram;
@ -693,8 +697,22 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
static const char MASTER_TAG[] = "test_master";
static const char SLAVE_TAG[] = "test_slave";
DRAM_ATTR static uint8_t master_send[] = {0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43};
DRAM_ATTR static uint8_t slave_send[] = { 0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 };
DRAM_ATTR static uint8_t master_send[] = {
0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
0x74,
0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
0x74,
0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
0x74,
};
DRAM_ATTR static uint8_t slave_send[] = {
0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
0xda,
0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
0xda,
0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
0xda,
};
static void master_deinit(spi_device_handle_t spi)
@ -1006,6 +1024,8 @@ esp_err_t check_data(spi_transaction_t *t, spi_dup_t dup, slave_rxdata_t *slave_
return ESP_OK;
}
int test_len[] = {1, 3, 5, 7, 9, 11, 33, 64};
static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
{
spi_transaction_t* trans = context->master_trans;
@ -1014,7 +1034,7 @@ static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
for (int i = 0; i < 8; i++ ) {
trans[i] = (spi_transaction_t) {
.flags = 0,
.rxlength = 8*(i*2+1),
.rxlength = 8*test_len[i],
.rx_buffer = rx_buf_ptr,
};
rx_buf_ptr += ((context->master_trans[i].rxlength + 31)/8)&(~3);
@ -1023,7 +1043,7 @@ static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
for (int i = 0; i < 8; i++ ) {
trans[i] = (spi_transaction_t) {
.flags = 0,
.length = 8*(i*2+1),
.length = 8*test_len[i],
.tx_buffer = master_send+i,
};
}
@ -1031,7 +1051,7 @@ static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
for (int i = 0; i < 8; i++ ) {
trans[i] = (spi_transaction_t) {
.flags = 0,
.length = 8*(i*2+1),
.length = 8*test_len[i],
.tx_buffer = master_send+i,
.rx_buffer = rx_buf_ptr,
};
@ -1042,7 +1062,7 @@ static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
for (int i = 0; i < 8; i ++) {
context->slave_trans[i] = (slave_txdata_t) {
.start = slave_send + 4*(i%3),
.len = 256,
.len = 512,
};
}
}
@ -1073,7 +1093,7 @@ typedef struct {
#define ESP_SPI_SLAVE_MAX_FREQ_SYNC SPI_MASTER_FREQ_40M
static test_timing_config_t timing_master_conf_t[] = {/**/
static test_timing_config_t timing_master_conf_t[] = {
{ .cfg_name = "FULL_DUP, MASTER IOMUX",
.freq_limit = SPI_MASTER_FREQ_13M,
.dup = FULL_DUPLEX,

View File

@ -32,6 +32,8 @@ static const char *TAG = "esp-tls";
#define ESP_LOGE(TAG, ...) printf(__VA_ARGS__);
#endif
#define DEFAULT_TIMEOUT_MS -1
static struct addrinfo *resolve_host_name(const char *host, size_t hostlen)
{
struct addrinfo hints;
@ -74,7 +76,13 @@ static ssize_t tls_read(esp_tls_t *tls, char *data, size_t datalen)
return ret;
}
static int esp_tcp_connect(const char *host, int hostlen, int port)
static void ms_to_timeval(int timeout_ms, struct timeval *tv)
{
tv->tv_sec = timeout_ms / 1000;
tv->tv_usec = (timeout_ms % 1000) * 1000;
}
static int esp_tcp_connect(const char *host, int hostlen, int port, int timeout_ms)
{
struct addrinfo *res = resolve_host_name(host, hostlen);
if (!res) {
@ -103,6 +111,12 @@ static int esp_tcp_connect(const char *host, int hostlen, int port)
goto err_freesocket;
}
if (timeout_ms >= 0) {
struct timeval tv;
ms_to_timeval(timeout_ms, &tv);
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
}
ret = connect(fd, addr_ptr, res->ai_addrlen);
if (ret < 0) {
ESP_LOGE(TAG, "Failed to connnect to host (errno %d)", errno);
@ -266,7 +280,13 @@ static ssize_t tls_write(esp_tls_t *tls, const char *data, size_t datalen)
*/
esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg)
{
int sockfd = esp_tcp_connect(hostname, hostlen, port);
int sockfd;
if (cfg) {
sockfd = esp_tcp_connect(hostname, hostlen, port, cfg->timeout_ms);
} else {
sockfd = esp_tcp_connect(hostname, hostlen, port, DEFAULT_TIMEOUT_MS);
}
if (sockfd < 0) {
return NULL;
}
@ -324,3 +344,12 @@ esp_tls_t *esp_tls_conn_http_new(const char *url, const esp_tls_cfg_t *cfg)
return esp_tls_conn_new(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len,
get_port(url, &u), cfg);
}
size_t esp_tls_get_bytes_avail(esp_tls_t *tls)
{
if (!tls) {
ESP_LOGE(TAG, "empty arg passed to esp_tls_get_bytes_avail()");
return ESP_FAIL;
}
return mbedtls_ssl_get_bytes_avail(&tls->ssl);
}

View File

@ -18,7 +18,6 @@
#include <sys/socket.h>
#include <fcntl.h>
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/esp_debug.h"
@ -48,12 +47,14 @@ typedef struct esp_tls_cfg {
const unsigned char *cacert_pem_buf; /*!< Certificate Authority's certificate in a buffer */
const unsigned int cacert_pem_bytes; /*!< Size of Certificate Authority certificate
unsigned int cacert_pem_bytes; /*!< Size of Certificate Authority certificate
pointed to by cacert_pem_buf */
bool non_block; /*!< Configure non-blocking mode. If set to true the
underneath socket will be configured in non
blocking mode after tls session is established */
int timeout_ms; /*!< Network timeout in milliseconds */
} esp_tls_cfg_t;
/**
@ -165,6 +166,21 @@ static inline ssize_t esp_tls_conn_read(esp_tls_t *tls, void *data, size_t data
*/
void esp_tls_conn_delete(esp_tls_t *tls);
/**
* @brief Return the number of application data bytes remaining to be
* read from the current record
*
* This API is a wrapper over mbedtls's mbedtls_ssl_get_bytes_avail() API.
*
* @param[in] tls pointer to esp-tls as esp-tls handle.
*
* @return
* - -1 in case of invalid arg
* - bytes available in the application data
* record read buffer
*/
size_t esp_tls_get_bytes_avail(esp_tls_t *tls);
#ifdef __cplusplus
}
#endif

View File

@ -687,18 +687,39 @@ choice ESP32_RTC_CLOCK_SOURCE
default ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
help
Choose which clock is used as RTC clock source.
- "Internal 150kHz oscillator" option provides lowest deep sleep current
consumption, and does not require extra external components. However
frequency stability with respect to temperature is poor, so time may
drift in deep/light sleep modes.
- "External 32kHz crystal" provides better frequency stability, at the
expense of slightly higher (1uA) deep sleep current consumption.
- "External 32kHz oscillator" allows using 32kHz clock generated by an
external circuit. In this case, external clock signal must be connected
to 32K_XP pin. Amplitude should be <1.2V in case of sine wave signal,
and <1V in case of square wave signal. Common mode voltage should be
0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude.
Additionally, 1nF capacitor must be connected between 32K_XN pin and
ground. 32K_XN pin can not be used as a GPIO in this case.
- "Internal 8.5MHz oscillator divided by 256" option results in higher
deep sleep current (by 5uA) but has better frequency stability than
the internal 150kHz oscillator. It does not require external components.
config ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
bool "Internal 150kHz RC oscillator"
config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
bool "External 32kHz crystal"
config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC
bool "External 32kHz oscillator at 32K_XP pin"
config ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256
bool "Internal 8.5MHz oscillator, divided by 256 (~33kHz)"
endchoice
config ESP32_RTC_CLK_CAL_CYCLES
int "Number of cycles for RTC_SLOW_CLK calibration"
default 3000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
default 1024 if ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
range 0 27000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
range 0 27000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL || ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC || ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256
range 0 32766 if ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
help
When the startup code initializes RTC_SLOW_CLK, it can perform

View File

@ -21,7 +21,7 @@
#include "soc/cpu.h"
#include "soc/rtc_cntl_reg.h"
#include "rom/ets_sys.h"
#include "esp_system.h"
#include "esp_system_internal.h"
#include "driver/rtc_cntl.h"
#include "freertos/FreeRTOS.h"
@ -42,6 +42,7 @@ static void rtc_brownout_isr_handler()
* at the same time as the following ets_printf.
*/
esp_cpu_stall(!xPortGetCoreID());
esp_reset_reason_set_hint(ESP_RST_BROWNOUT);
ets_printf("\r\nBrownout detector was triggered\r\n\r\n");
esp_restart_noos();
}

View File

@ -40,7 +40,23 @@
#define MHZ (1000000)
static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk);
/* Indicates that this 32k oscillator gets input from external oscillator, rather
* than a crystal.
*/
#define EXT_OSC_FLAG BIT(3)
/* This is almost the same as rtc_slow_freq_t, except that we define
* an extra enum member for the external 32k oscillator.
* For convenience, lower 2 bits should correspond to rtc_slow_freq_t values.
*/
typedef enum {
SLOW_CLK_150K = RTC_SLOW_FREQ_RTC, //!< Internal 150 kHz RC oscillator
SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL
SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256
SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin
} slow_clk_sel_t;
static void select_rtc_slow_clk(slow_clk_sel_t slow_clk);
// g_ticks_us defined in ROMs for PRO and APP CPU
extern uint32_t g_ticks_per_us_pro;
@ -71,50 +87,47 @@ void esp_clk_init(void)
rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M);
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL);
#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)
select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC);
#elif defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256)
select_rtc_slow_clk(SLOW_CLK_8MD256);
#else
select_rtc_slow_clk(RTC_SLOW_FREQ_RTC);
#endif
uint32_t freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
rtc_cpu_freq_t freq = RTC_CPU_FREQ_80M;
switch(freq_mhz) {
case 240:
freq = RTC_CPU_FREQ_240M;
break;
case 160:
freq = RTC_CPU_FREQ_160M;
break;
default:
freq_mhz = 80;
/* falls through */
case 80:
freq = RTC_CPU_FREQ_80M;
break;
}
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;
const uint32_t new_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config);
assert(res);
// Wait for UART TX to finish, otherwise some UART output will be lost
// when switching APB frequency
uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
uint32_t freq_before = rtc_clk_cpu_freq_value(rtc_clk_cpu_freq_get()) / MHZ ;
rtc_clk_cpu_freq_set(freq);
rtc_clk_cpu_freq_set_config(&new_config);
// Re calculate the ccount to make time calculation correct.
uint32_t freq_after = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
XTHAL_SET_CCOUNT( XTHAL_GET_CCOUNT() * freq_after / freq_before );
XTHAL_SET_CCOUNT( XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz );
}
int IRAM_ATTR esp_clk_cpu_freq(void)
{
return g_ticks_per_us_pro * 1000000;
return g_ticks_per_us_pro * MHZ;
}
int IRAM_ATTR esp_clk_apb_freq(void)
{
return MIN(g_ticks_per_us_pro, 80) * 1000000;
return MIN(g_ticks_per_us_pro, 80) * MHZ;
}
int IRAM_ATTR esp_clk_xtal_freq(void)
{
return rtc_clk_xtal_freq_get() * MHZ;
}
void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
@ -124,16 +137,12 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
g_ticks_per_us_app = ticks_per_us;
}
static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
static void select_rtc_slow_clk(slow_clk_sel_t slow_clk)
{
rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V;
uint32_t cal_val = 0;
uint32_t wait = 0;
uint32_t freq_hz = ((slow_clk == RTC_SLOW_FREQ_32K_XTAL) ? 32768 : 150000);
uint32_t warning_timeout = 3 /* sec */ * freq_hz /* Hz */ / (SLOW_CLK_CAL_CYCLES + 1);
warning_timeout = ((warning_timeout == 0) ? 3 /* sec */ : warning_timeout);
bool changing_clock_to_150k = false;
do {
if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) {
if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) {
/* 32k XTAL oscillator needs to be enabled and running before it can
* be used. Hardware doesn't have a direct way of checking if the
* oscillator is running. Here we use rtc_clk_cal function to count
@ -142,25 +151,23 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
* will time out, returning 0.
*/
ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up");
rtc_clk_32k_enable(true);
if (slow_clk == SLOW_CLK_32K_XTAL) {
rtc_clk_32k_enable(true);
} else if (slow_clk == SLOW_CLK_32K_EXT_OSC) {
rtc_clk_32k_enable_external();
}
// When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup.
if (SLOW_CLK_CAL_CYCLES > 0) {
cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES);
if (cal_val == 0 || cal_val < 15000000L) {
ESP_EARLY_LOGE(TAG, "RTC: Not found External 32 kHz XTAL. Switching to Internal 150 kHz RC chain");
slow_clk = RTC_SLOW_FREQ_RTC;
changing_clock_to_150k = true;
ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator");
rtc_slow_freq = RTC_SLOW_FREQ_RTC;
}
}
} else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) {
rtc_clk_8m_enable(true, true);
}
rtc_clk_slow_freq_set(slow_clk);
if (changing_clock_to_150k == true && wait > 1){
// This helps when there are errors when switching the clock from External 32 kHz XTAL to Internal 150 kHz RC chain.
rtc_clk_32k_enable(false);
uint32_t min_bootstrap = 5; // Min bootstrapping for continue switching the clock.
rtc_clk_32k_bootstrap(min_bootstrap);
rtc_clk_32k_enable(true);
}
rtc_clk_slow_freq_set(rtc_slow_freq);
if (SLOW_CLK_CAL_CYCLES > 0) {
/* TODO: 32k XTAL oscillator has some frequency drift at startup.
@ -171,9 +178,6 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL;
cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz());
}
if (++wait % warning_timeout == 0) {
ESP_EARLY_LOGW(TAG, "still waiting for source selection RTC");
}
} while (cal_val == 0);
ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val);
esp_clk_slowclk_cal_set(cal_val);

View File

@ -125,11 +125,11 @@ static const esp_err_msg_t esp_err_msg_table[] = {
ERR_TBL_IT(ESP_ERR_NVS_INVALID_HANDLE), /* 4359 0x1107 Handle has been closed or is NULL */
# endif
# ifdef ESP_ERR_NVS_REMOVE_FAILED
ERR_TBL_IT(ESP_ERR_NVS_REMOVE_FAILED), /* 4360 0x1108 The value wasnt updated because flash
write operation has failed. The value was
written however, and update will be finished
after re-initialization of nvs, provided
that flash operation doesnt fail again. */
ERR_TBL_IT(ESP_ERR_NVS_REMOVE_FAILED), /* 4360 0x1108 The value wasnt updated because flash write
operation has failed. The value was written
however, and update will be finished after
re-initialization of nvs, provided that
flash operation doesnt fail again. */
# endif
# ifdef ESP_ERR_NVS_KEY_TOO_LONG
ERR_TBL_IT(ESP_ERR_NVS_KEY_TOO_LONG), /* 4361 0x1109 Key name is too long */

View File

@ -0,0 +1,56 @@
// 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_system.h"
/**
* @brief Internal function to restart PRO and APP CPUs.
*
* @note This function should not be called from FreeRTOS applications.
* Use esp_restart instead.
*
* This is an internal function called by esp_restart. It is called directly
* by the panic handler and brownout detector interrupt.
*/
void esp_restart_noos() __attribute__ ((noreturn));
/**
* @brief Internal function to set reset reason hint
*
* The hint is used do distinguish different reset reasons when software reset
* is performed.
*
* The hint is stored in RTC store register, RTC_RESET_CAUSE_REG.
*
* @param hint Desired esp_reset_reason_t value for the real reset reason
*/
void esp_reset_reason_set_hint(esp_reset_reason_t hint);
/**
* @brief Internal function to get the reset hint value
* @return - Reset hint value previously stored into RTC_RESET_CAUSE_REG using
* esp_reset_reason_set_hint function
* - ESP_RST_UNKNOWN if the value in RTC_RESET_CAUSE_REG is invalid
*/
esp_reset_reason_t esp_reset_reason_get_hint(void);
#ifdef __cplusplus
}
#endif

View File

@ -31,8 +31,10 @@ extern "C" {
* Pass a pointer to this structure as an argument to esp_pm_configure function.
*/
typedef struct {
rtc_cpu_freq_t max_cpu_freq; /*!< Maximum CPU frequency to use */
rtc_cpu_freq_t min_cpu_freq; /*!< Minimum CPU frequency to use when no frequency locks are taken */
rtc_cpu_freq_t max_cpu_freq __attribute__((deprecated)); /*!< Maximum CPU frequency to use. Deprecated, use max_freq_mhz instead. */
int max_freq_mhz; /*!< Maximum CPU frequency, in MHz */
rtc_cpu_freq_t min_cpu_freq __attribute__((deprecated)); /*!< Minimum CPU frequency to use when no frequency locks are taken. Deprecated, use min_freq_mhz instead. */
int min_freq_mhz; /*!< Minimum CPU frequency to use when no locks are taken, in MHz */
bool light_sleep_enable; /*!< Enter light sleep when no locks are taken */
} esp_pm_config_esp32_t;

View File

@ -62,6 +62,17 @@ int esp_clk_cpu_freq(void);
*/
int esp_clk_apb_freq(void);
/**
* @brief Return frequency of the main XTAL
*
* Frequency of the main XTAL can be either auto-detected or set at compile
* time (see CONFIG_ESP32_XTAL_FREQ_SEL sdkconfig option). In both cases, this
* function returns the actual value at run time.
*
* @return XTAL frequency, in Hz
*/
int esp_clk_xtal_freq(void);
/**
* @brief Read value of RTC counter, converting it to microseconds

View File

@ -166,7 +166,7 @@ typedef enum {
MESH_EVENT_ROUTING_TABLE_REMOVE, /**< routing table is changed by removing leave children */
MESH_EVENT_PARENT_CONNECTED, /**< parent is connected on station interface */
MESH_EVENT_PARENT_DISCONNECTED, /**< parent is disconnected on station interface */
MESH_EVENT_NO_PARNET_FOUND, /**< no parent found */
MESH_EVENT_NO_PARENT_FOUND, /**< no parent found */
MESH_EVENT_LAYER_CHANGE, /**< layer changes over the mesh network */
MESH_EVENT_TODS_STATE, /**< state represents if root is able to access external IP network */
MESH_EVENT_VOTE_STARTED, /**< the process of voting a new root is started either by children or by root */
@ -771,9 +771,13 @@ esp_err_t esp_mesh_set_id(const mesh_addr_t *id);
esp_err_t esp_mesh_get_id(mesh_addr_t *id);
/**
* @brief set device type over the mesh network(Unimplemented)
* @brief specify device type over the mesh network
* - MESH_ROOT: designates the root node for a mesh network
* - MESH_LEAF: designates a device as a standalone Wi-Fi station
*
* @param type device type
* @attention This API shall be called before esp_mesh_start().
*
* @param type device type (only support MESH_ROOT, MESH_LEAF)
*
* @return
* - ESP_OK
@ -782,9 +786,7 @@ esp_err_t esp_mesh_get_id(mesh_addr_t *id);
esp_err_t esp_mesh_set_type(mesh_type_t type);
/**
* @brief get device type over mesh network
*
* @attention This API shall be called after having received the event MESH_EVENT_PARENT_CONNECTED.
* @brief get device type over the mesh network
*
* @return mesh type
*
@ -792,7 +794,7 @@ esp_err_t esp_mesh_set_type(mesh_type_t type);
mesh_type_t esp_mesh_get_type(void);
/**
* @brief set max layer configuration(max:15, default:15)
* @brief set max layer configuration(max:25, default:25)
*
* @attention This API shall be called before esp_mesh_start().
*
@ -1320,6 +1322,33 @@ esp_err_t esp_mesh_scan_get_ap_record(wifi_ap_record_t *ap_record, void *buffer)
*/
esp_err_t esp_mesh_flush_upstream_packets(void);
/**
* @brief get the number of nodes in the subnet of a specific child
*
* @param child_mac an associated child address of this device
* @param nodes_num pointer to the number of nodes in the subnet of a specific child
*
* @return
* - ESP_OK
* - ESP_ERR_MESH_NOT_START
* - ESP_ERR_MESH_ARGUMENT
*/
esp_err_t esp_mesh_get_subnet_nodes_num(const mesh_addr_t *child_mac, int *nodes_num);
/**
* @brief get nodes in the subnet of a specific child
*
* @param child_mac an associated child address of this device
* @param nodes pointer to nodes in the subnet of a specific child
* @param nodes_num the number of nodes in the subnet of a specific child
*
* @return
* - ESP_OK
* - ESP_ERR_MESH_NOT_START
* - ESP_ERR_MESH_ARGUMENT
*/
esp_err_t esp_mesh_get_subnet_nodes_list(const mesh_addr_t *child_mac, mesh_addr_t *nodes, int nodes_num);
#ifdef __cplusplus
}
#endif

View File

@ -31,12 +31,32 @@ typedef enum {
ESP_MAC_ETH,
} esp_mac_type_t;
/** @cond */
#define TWO_UNIVERSAL_MAC_ADDR 2
#define FOUR_UNIVERSAL_MAC_ADDR 4
#define UNIVERSAL_MAC_ADDR_NUM CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS
/** @endcond */
/**
* @attention application don't need to call this function anymore. It do nothing and will
* @brief Reset reasons
*/
typedef enum {
ESP_RST_UNKNOWN, //!< Reset reason can not be determined
ESP_RST_POWERON, //!< Reset due to power-on event
ESP_RST_EXT, //!< Reset by external pin (not applicable for ESP32)
ESP_RST_SW, //!< Software reset via esp_restart
ESP_RST_PANIC, //!< Software reset due to exception/panic
ESP_RST_INT_WDT, //!< Reset (software or hardware) due to interrupt watchdog
ESP_RST_TASK_WDT, //!< Reset due to task watchdog
ESP_RST_WDT, //!< Reset due to other watchdogs
ESP_RST_DEEPSLEEP, //!< Reset after exiting deep sleep mode
ESP_RST_BROWNOUT, //!< Brownout reset (software or hardware)
ESP_RST_SDIO, //!< Reset over SDIO
} esp_reset_reason_t;
/** @cond */
/**
* @attention Applications don't need to call this function anymore. It does nothing and will
* be removed in future version.
*/
void system_init(void) __attribute__ ((deprecated));
@ -48,13 +68,18 @@ void system_init(void) __attribute__ ((deprecated));
* This name will be removed in a future release.
*/
void system_restore(void) __attribute__ ((deprecated));
/** @endcond */
/**
* Shutdown handler type
*/
typedef void (*shutdown_handler_t)(void);
/**
* @brief Register shutdown handler
*
* This function allows you to register a handler that gets invoked before a
* systematic shutdown of the chip.
* This function allows you to register a handler that gets invoked before
* the application is restarted using esp_restart function.
*/
esp_err_t esp_register_shutdown_handler(shutdown_handler_t handle);
@ -68,17 +93,7 @@ esp_err_t esp_register_shutdown_handler(shutdown_handler_t handle);
*/
void esp_restart(void) __attribute__ ((noreturn));
/**
* @brief Internal function to restart PRO and APP CPUs.
*
* @note This function should not be called from FreeRTOS applications.
* Use esp_restart instead.
*
* This is an internal function called by esp_restart. It is called directly
* by the panic handler and brownout detector interrupt.
*/
void esp_restart_noos() __attribute__ ((noreturn));
/** @cond */
/**
* @brief Restart system.
*
@ -86,7 +101,15 @@ void esp_restart_noos() __attribute__ ((noreturn));
* This name will be removed in a future release.
*/
void system_restart(void) __attribute__ ((deprecated, noreturn));
/** @endcond */
/**
* @brief Get reason of last reset
* @return See description of esp_reset_reason_t for explanation of each value.
*/
esp_reset_reason_t esp_reset_reason(void);
/** @cond */
/**
* @brief Get system time, unit: microsecond.
*
@ -94,6 +117,7 @@ void system_restart(void) __attribute__ ((deprecated, noreturn));
* This definition will be removed in a future release.
*/
uint32_t system_get_time(void) __attribute__ ((deprecated));
/** @endcond */
/**
* @brief Get the size of available heap.
@ -105,6 +129,7 @@ uint32_t system_get_time(void) __attribute__ ((deprecated));
*/
uint32_t esp_get_free_heap_size(void);
/** @cond */
/**
* @brief Get the size of available heap.
*
@ -114,6 +139,7 @@ uint32_t esp_get_free_heap_size(void);
* @return Available heap size, in bytes.
*/
uint32_t system_get_free_heap_size(void) __attribute__ ((deprecated));
/** @endcond */
/**
* @brief Get the minimum heap that has ever been available
@ -187,6 +213,7 @@ esp_err_t esp_efuse_mac_get_custom(uint8_t *mac);
*/
esp_err_t esp_efuse_mac_get_default(uint8_t *mac);
/** @cond */
/**
* @brief Read hardware MAC address from efuse.
*
@ -209,6 +236,7 @@ esp_err_t esp_efuse_read_mac(uint8_t *mac) __attribute__ ((deprecated));
* @return ESP_OK on success
*/
esp_err_t system_efuse_read_mac(uint8_t *mac) __attribute__ ((deprecated));
/** @endcond */
/**
* @brief Read base MAC address and set MAC address of the interface.
@ -240,6 +268,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type);
*/
esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac);
/** @cond */
/**
* Get SDK version
*
@ -248,6 +277,7 @@ esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac)
* @return constant string "master"
*/
const char* system_get_sdk_version(void) __attribute__ ((deprecated));
/** @endcond */
/**
* Get IDF version
@ -264,13 +294,11 @@ typedef enum {
CHIP_ESP32 = 1, //!< ESP32
} esp_chip_model_t;
/**
* Chip feature flags, used in esp_chip_info_t
*/
#define CHIP_FEATURE_EMB_FLASH BIT(0)
#define CHIP_FEATURE_WIFI_BGN BIT(1)
#define CHIP_FEATURE_BLE BIT(4)
#define CHIP_FEATURE_BT BIT(5)
/* Chip feature flags, used in esp_chip_info_t */
#define CHIP_FEATURE_EMB_FLASH BIT(0) //!< Chip has embedded flash memory
#define CHIP_FEATURE_WIFI_BGN BIT(1) //!< Chip has 2.4GHz WiFi
#define CHIP_FEATURE_BLE BIT(4) //!< Chip has Bluetooth LE
#define CHIP_FEATURE_BT BIT(5) //!< Chip has Bluetooth Classic
/**
* @brief The structure represents information about the chip

View File

@ -303,7 +303,13 @@ esp_err_t esp_wifi_restore(void);
*
* @attention 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode
* @attention 2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect.
*
* @attention 3. The scanning triggered by esp_wifi_start_scan() will not be effective until connection between ESP32 and the AP is established.
* If ESP32 is scanning and connecting at the same time, ESP32 will abort scanning and return a warning message and error
* number ESP_ERR_WIFI_STATE.
* If you want to do reconnection after ESP32 received disconnect event, remember to add the maximum retry time, otherwise the called
* scan will not work. This is especially true when the AP doesn't exist, and you still try reconnection after ESP32 received disconnect
* event with the reason code WIFI_REASON_NO_AP_FOUND.
*
* @return
* - ESP_OK: succeed
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
@ -366,6 +372,7 @@ esp_err_t esp_wifi_deauth_sta(uint16_t aid);
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
* - ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start
* - ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout
* - ESP_ERR_WIFI_STATE: wifi still connecting when invoke esp_wifi_scan_start
* - others: refer to error code in esp_err.h
*/
esp_err_t esp_wifi_scan_start(const wifi_scan_config_t *config, bool block);

View File

@ -68,6 +68,7 @@ extern "C" {
#define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG
#define RTC_APB_FREQ_REG RTC_CNTL_STORE5_REG
#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG
#define RTC_RESET_CAUSE_REG RTC_CNTL_STORE6_REG
#define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG

View File

@ -32,6 +32,7 @@ SECTIONS
_rtc_bss_start = ABSOLUTE(.);
*rtc_wake_stub*.*(.bss .bss.*)
*rtc_wake_stub*.*(COMMON)
*(.rtc.bss)
_rtc_bss_end = ABSOLUTE(.);
} > rtc_slow_seg

View File

@ -176,6 +176,7 @@ PROVIDE ( lld_evt_elt_wait_get = 0x400468e4 );
PROVIDE ( lld_evt_get_next_free_slot = 0x4004692c );
PROVIDE ( lld_pdu_adv_pk_desc_tab = 0x3ff98c70 );
PROVIDE ( lld_pdu_llcp_pk_desc_tab = 0x3ff98b68 );
PROVIDE ( lld_pdu_tx_flush_list = 0x4004a760 );
PROVIDE ( lld_pdu_pack = 0x4004ab14 );
PROVIDE ( LLM_AA_CT1 = 0x3ff98d8a );
PROVIDE ( LLM_AA_CT2 = 0x3ff98d88 );
@ -1620,6 +1621,7 @@ PROVIDE ( hci_tl_env = 0x3ffb8154 );
PROVIDE ( ld_acl_env = 0x3ffb8258 );
PROVIDE ( ea_env = 0x3ffb80ec );
PROVIDE ( lc_sco_data_path_config = 0x3ffb81f8 );
PROVIDE ( lc_sco_env = 0x3ffb81fc );
PROVIDE ( ld_active_ch_map = 0x3ffb8334 );
PROVIDE ( ld_bcst_acl_env = 0x3ffb8274 );
PROVIDE ( ld_csb_rx_env = 0x3ffb8278 );

@ -1 +1 @@
Subproject commit 3a57e719887cfa3f72abc27e7d3102800cd7eb65
Subproject commit 4c69c1ad8da7a9cbe8e27598b8c91780ac0b5068

View File

@ -40,7 +40,7 @@
#include "esp_spi_flash.h"
#include "esp_cache_err_int.h"
#include "esp_app_trace.h"
#include "esp_system.h"
#include "esp_system_internal.h"
#include "sdkconfig.h"
#if CONFIG_SYSVIEW_ENABLE
#include "SEGGER_RTT.h"
@ -121,6 +121,20 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, s
abort();
}
/* These two weak stubs for esp_reset_reason_{get,set}_hint are used when
* the application does not call esp_reset_reason() function, and
* reset_reason.c is not linked into the output file.
*/
void __attribute__((weak)) esp_reset_reason_set_hint(esp_reset_reason_t hint)
{
}
esp_reset_reason_t __attribute__((weak)) esp_reset_reason_get_hint(void)
{
return ESP_RST_UNKNOWN;
}
static bool abort_called;
static __attribute__((noreturn)) inline void invoke_abort()
@ -147,6 +161,12 @@ void abort()
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
ets_printf("abort() was called at PC 0x%08x on core %d\r\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID());
#endif
/* Calling code might have set other reset reason hint (such as Task WDT),
* don't overwrite that.
*/
if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) {
esp_reset_reason_set_hint(ESP_RST_PANIC);
}
invoke_abort();
}
@ -234,6 +254,10 @@ void panicHandler(XtExcFrame *frame)
}
#endif //!CONFIG_FREERTOS_UNICORE
if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || frame->exccause == PANIC_RSN_INTWDT_CPU1) {
esp_reset_reason_set_hint(ESP_RST_INT_WDT);
}
haltOtherCore();
esp_dport_access_int_abort();
panicPutStr("Guru Meditation Error: Core ");
@ -333,6 +357,7 @@ void xt_unhandled_exception(XtExcFrame *frame)
return;
}
panicPutStr(". Exception was unhandled.\r\n");
esp_reset_reason_set_hint(ESP_RST_PANIC);
}
commonErrorHandler(frame);
}
@ -382,7 +407,7 @@ static void esp_panic_dig_reset()
// make sure all the panic handler output is sent from UART FIFO
uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
// switch to XTAL (otherwise we will keep running from the PLL)
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
rtc_clk_cpu_freq_set_xtal();
// reset the digital part
esp_cpu_unstall(PRO_CPU_NUM);
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);

View File

@ -51,6 +51,11 @@
*/
#define LIGHT_SLEEP_EARLY_WAKEUP_US 100
/* Minimal divider at which REF_CLK_FREQ can be obtained */
#define REF_CLK_DIV_MIN 10
#define MHZ 1000000
#ifdef CONFIG_PM_PROFILING
#define WITH_PROFILING
#endif
@ -80,44 +85,20 @@ static uint32_t s_ccount_mul;
*/
static volatile bool s_need_update_ccompare[portNUM_PROCESSORS];
/* When no RTOS tasks are active, these locks are released to allow going into
* a lower power mode. Used by ISR hook and idle hook.
*/
static esp_pm_lock_handle_t s_rtos_lock_handle[portNUM_PROCESSORS];
/* A flag indicating that Idle hook has run on a given CPU;
* Next interrupt on the same CPU will take s_rtos_lock_handle.
*/
static bool s_core_idle[portNUM_PROCESSORS];
/* g_ticks_us defined in ROM for PRO CPU */
extern uint32_t g_ticks_per_us_pro;
/* When no RTOS tasks are active, these locks are released to allow going into
* a lower power mode. Used by ISR hook and idle hook.
*/
static esp_pm_lock_handle_t s_rtos_lock_handle[portNUM_PROCESSORS];
/* Lookup table of CPU frequencies to be used in each mode.
/* Lookup table of CPU frequency configs to be used in each mode.
* Initialized by esp_pm_impl_init and modified by esp_pm_configure.
*/
rtc_cpu_freq_t s_cpu_freq_by_mode[PM_MODE_COUNT];
/* Lookup table of CPU ticks per microsecond for each RTC_CPU_FREQ_ value.
* Essentially the same as returned by rtc_clk_cpu_freq_value(), but without
* the function call. Not const because XTAL frequency is only known at run time.
*/
static uint32_t s_cpu_freq_to_ticks[] = {
[RTC_CPU_FREQ_XTAL] = 0, /* This is set by esp_pm_impl_init */
[RTC_CPU_FREQ_80M] = 80,
[RTC_CPU_FREQ_160M] = 160,
[RTC_CPU_FREQ_240M] = 240,
[RTC_CPU_FREQ_2M] = 2
};
/* Lookup table of names for each RTC_CPU_FREQ_ value. Used for logging only. */
static const char* s_freq_names[] __attribute__((unused)) = {
[RTC_CPU_FREQ_XTAL] = "XTAL",
[RTC_CPU_FREQ_80M] = "80",
[RTC_CPU_FREQ_160M] = "160",
[RTC_CPU_FREQ_240M] = "240",
[RTC_CPU_FREQ_2M] = "2"
};
rtc_cpu_freq_config_t s_cpu_freq_by_mode[PM_MODE_COUNT];
/* Whether automatic light sleep is enabled */
static bool s_light_sleep_en = false;
@ -167,21 +148,6 @@ pm_mode_t esp_pm_impl_get_mode(esp_pm_lock_type_t type, int arg)
}
}
/* rtc_cpu_freq_t enum is not ordered by frequency, so convert to MHz,
* figure out the maximum value, then convert back to rtc_cpu_freq_t.
*/
static rtc_cpu_freq_t max_freq_of(rtc_cpu_freq_t f1, rtc_cpu_freq_t f2)
{
int f1_hz = rtc_clk_cpu_freq_value(f1);
int f2_hz = rtc_clk_cpu_freq_value(f2);
int f_max_hz = MAX(f1_hz, f2_hz);
rtc_cpu_freq_t result = RTC_CPU_FREQ_XTAL;
if (!rtc_clk_cpu_freq_from_mhz(f_max_hz/1000000, &result)) {
assert(false && "unsupported frequency");
}
return result;
}
esp_err_t esp_pm_configure(const void* vconfig)
{
#ifndef CONFIG_PM_ENABLE
@ -195,46 +161,66 @@ esp_err_t esp_pm_configure(const void* vconfig)
}
#endif
if (config->min_cpu_freq == RTC_CPU_FREQ_2M) {
/* Minimal APB frequency to achieve 1MHz REF_TICK frequency is 5 MHz */
return ESP_ERR_NOT_SUPPORTED;
int min_freq_mhz = config->min_freq_mhz;
int max_freq_mhz = config->max_freq_mhz;
if (min_freq_mhz == 0 && max_freq_mhz == 0) {
/* For compatibility, handle deprecated fields, min_cpu_freq and max_cpu_freq. */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
min_freq_mhz = rtc_clk_cpu_freq_value(config->min_cpu_freq) / MHZ;
max_freq_mhz = rtc_clk_cpu_freq_value(config->max_cpu_freq) / MHZ;
#pragma GCC diagnostic pop
}
rtc_cpu_freq_t min_freq = config->min_cpu_freq;
rtc_cpu_freq_t max_freq = config->max_cpu_freq;
int min_freq_mhz = rtc_clk_cpu_freq_value(min_freq);
int max_freq_mhz = rtc_clk_cpu_freq_value(max_freq);
if (min_freq_mhz > max_freq_mhz) {
return ESP_ERR_INVALID_ARG;
}
rtc_cpu_freq_t apb_max_freq = max_freq; /* CPU frequency in APB_MAX mode */
if (max_freq == RTC_CPU_FREQ_240M) {
rtc_cpu_freq_config_t freq_config;
if (!rtc_clk_cpu_freq_mhz_to_config(min_freq_mhz, &freq_config)) {
ESP_LOGW(TAG, "invalid min_freq_mhz value (%d)", min_freq_mhz);
return ESP_ERR_INVALID_ARG;
}
int xtal_freq_mhz = (int) rtc_clk_xtal_freq_get();
if (min_freq_mhz < xtal_freq_mhz && min_freq_mhz * MHZ / REF_CLK_FREQ < REF_CLK_DIV_MIN) {
ESP_LOGW(TAG, "min_freq_mhz should be >= %d", REF_CLK_FREQ * REF_CLK_DIV_MIN / MHZ);
return ESP_ERR_INVALID_ARG;
}
if (!rtc_clk_cpu_freq_mhz_to_config(max_freq_mhz, &freq_config)) {
ESP_LOGW(TAG, "invalid max_freq_mhz value (%d)", max_freq_mhz);
return ESP_ERR_INVALID_ARG;
}
int apb_max_freq = max_freq_mhz; /* CPU frequency in APB_MAX mode */
if (max_freq_mhz == 240) {
/* We can't switch between 240 and 80/160 without disabling PLL,
* so use 240MHz CPU frequency when 80MHz APB frequency is requested.
*/
apb_max_freq = RTC_CPU_FREQ_240M;
} else if (max_freq == RTC_CPU_FREQ_160M || max_freq == RTC_CPU_FREQ_80M) {
apb_max_freq = 240;
} else if (max_freq_mhz == 160 || max_freq_mhz == 80) {
/* Otherwise, can use 80MHz
* CPU frequency when 80MHz APB frequency is requested.
*/
apb_max_freq = RTC_CPU_FREQ_80M;
apb_max_freq = 80;
}
apb_max_freq = max_freq_of(apb_max_freq, min_freq);
apb_max_freq = MAX(apb_max_freq, min_freq_mhz);
ESP_LOGI(TAG, "Frequency switching config: "
"CPU_MAX: %s, APB_MAX: %s, APB_MIN: %s, Light sleep: %s",
s_freq_names[max_freq],
s_freq_names[apb_max_freq],
s_freq_names[min_freq],
"CPU_MAX: %d, APB_MAX: %d, APB_MIN: %d, Light sleep: %s",
max_freq_mhz,
apb_max_freq,
min_freq_mhz,
config->light_sleep_enable ? "ENABLED" : "DISABLED");
portENTER_CRITICAL(&s_switch_lock);
s_cpu_freq_by_mode[PM_MODE_CPU_MAX] = max_freq;
s_cpu_freq_by_mode[PM_MODE_APB_MAX] = apb_max_freq;
s_cpu_freq_by_mode[PM_MODE_APB_MIN] = min_freq;
s_cpu_freq_by_mode[PM_MODE_LIGHT_SLEEP] = min_freq;
rtc_clk_cpu_freq_mhz_to_config(max_freq_mhz, &s_cpu_freq_by_mode[PM_MODE_CPU_MAX]);
rtc_clk_cpu_freq_mhz_to_config(apb_max_freq, &s_cpu_freq_by_mode[PM_MODE_APB_MAX]);
rtc_clk_cpu_freq_mhz_to_config(min_freq_mhz, &s_cpu_freq_by_mode[PM_MODE_APB_MIN]);
s_cpu_freq_by_mode[PM_MODE_LIGHT_SLEEP] = s_cpu_freq_by_mode[PM_MODE_APB_MIN];
s_light_sleep_en = config->light_sleep_enable;
s_config_changed = true;
portEXIT_CRITICAL(&s_switch_lock);
@ -310,7 +296,7 @@ static void IRAM_ATTR on_freq_update(uint32_t old_ticks_per_us, uint32_t ticks_p
}
/* Calculate new tick divisor */
_xt_tick_divisor = ticks_per_us * 1000000 / XT_TICK_PER_SEC;
_xt_tick_divisor = ticks_per_us * MHZ / XT_TICK_PER_SEC;
int core_id = xPortGetCoreID();
if (s_rtos_lock_handle[core_id] != NULL) {
@ -375,17 +361,18 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
s_config_changed = false;
portEXIT_CRITICAL_ISR(&s_switch_lock);
rtc_cpu_freq_t new_freq = s_cpu_freq_by_mode[new_mode];
rtc_cpu_freq_t old_freq;
rtc_cpu_freq_config_t new_config = s_cpu_freq_by_mode[new_mode];
rtc_cpu_freq_config_t old_config;
if (!config_changed) {
old_freq = s_cpu_freq_by_mode[s_mode];
old_config = s_cpu_freq_by_mode[s_mode];
} else {
old_freq = rtc_clk_cpu_freq_get();
rtc_clk_cpu_freq_get_config(&old_config);
}
if (new_freq != old_freq) {
uint32_t old_ticks_per_us = g_ticks_per_us_pro;
uint32_t new_ticks_per_us = s_cpu_freq_to_ticks[new_freq];
if (new_config.freq_mhz != old_config.freq_mhz) {
uint32_t old_ticks_per_us = old_config.freq_mhz;
uint32_t new_ticks_per_us = new_config.freq_mhz;
bool switch_down = new_ticks_per_us < old_ticks_per_us;
@ -393,7 +380,7 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
if (switch_down) {
on_freq_update(old_ticks_per_us, new_ticks_per_us);
}
rtc_clk_cpu_freq_set_fast(new_freq);
rtc_clk_cpu_freq_set_config_fast(&new_config);
if (!switch_down) {
on_freq_update(old_ticks_per_us, new_ticks_per_us);
}
@ -536,9 +523,9 @@ void esp_pm_impl_dump_stats(FILE* out)
/* don't display light sleep mode if it's not enabled */
continue;
}
fprintf(out, "%8s %6s %12lld %2d%%\n",
fprintf(out, "%8s %3dM %12lld %2d%%\n",
s_mode_names[i],
s_freq_names[s_cpu_freq_by_mode[i]],
s_cpu_freq_by_mode[i].freq_mhz,
time_in_mode[i],
(int) (time_in_mode[i] * 100 / now));
}
@ -547,7 +534,6 @@ void esp_pm_impl_dump_stats(FILE* out)
void esp_pm_impl_init()
{
s_cpu_freq_to_ticks[RTC_CPU_FREQ_XTAL] = rtc_clk_xtal_freq_get();
#ifdef CONFIG_PM_TRACE
esp_pm_trace_init();
#endif
@ -563,11 +549,11 @@ void esp_pm_impl_init()
/* Configure all modes to use the default CPU frequency.
* This will be modified later by a call to esp_pm_configure.
*/
rtc_cpu_freq_t default_freq;
if (!rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, &default_freq)) {
rtc_cpu_freq_config_t default_config;
if (!rtc_clk_cpu_freq_mhz_to_config(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, &default_config)) {
assert(false && "unsupported frequency");
}
for (size_t i = 0; i < PM_MODE_COUNT; ++i) {
s_cpu_freq_by_mode[i] = default_freq;
s_cpu_freq_by_mode[i] = default_config;
}
}

View File

@ -0,0 +1,126 @@
// 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 "esp_system.h"
#include "esp_system_internal.h"
#include "rom/rtc.h"
#include "soc/rtc_cntl_reg.h"
static void esp_reset_reason_clear_hint();
static esp_reset_reason_t s_reset_reason;
static esp_reset_reason_t get_reset_reason(RESET_REASON rtc_reset_reason, esp_reset_reason_t reset_reason_hint)
{
switch (rtc_reset_reason) {
case POWERON_RESET:
return ESP_RST_POWERON;
/* For ESP32, ESP_RST_EXT is never returned */
case SW_CPU_RESET:
case SW_RESET:
case EXT_CPU_RESET: /* unused */
if (reset_reason_hint == ESP_RST_PANIC ||
reset_reason_hint == ESP_RST_BROWNOUT ||
reset_reason_hint == ESP_RST_TASK_WDT ||
reset_reason_hint == ESP_RST_INT_WDT) {
return reset_reason_hint;
}
return ESP_RST_SW;
case DEEPSLEEP_RESET:
return ESP_RST_DEEPSLEEP;
case TG0WDT_SYS_RESET:
return ESP_RST_TASK_WDT;
case TG1WDT_SYS_RESET:
return ESP_RST_INT_WDT;
case OWDT_RESET:
case RTCWDT_SYS_RESET:
case RTCWDT_RTC_RESET:
case RTCWDT_CPU_RESET: /* unused */
case TGWDT_CPU_RESET: /* unused */
return ESP_RST_WDT;
case RTCWDT_BROWN_OUT_RESET: /* unused */
return ESP_RST_BROWNOUT;
case SDIO_RESET:
return ESP_RST_SDIO;
case INTRUSION_RESET: /* unused */
default:
return ESP_RST_UNKNOWN;
}
}
static void __attribute__((constructor)) esp_reset_reason_init(void)
{
esp_reset_reason_t hint = esp_reset_reason_get_hint();
s_reset_reason = get_reset_reason(rtc_get_reset_reason(PRO_CPU_NUM),
hint);
if (hint != ESP_RST_UNKNOWN) {
esp_reset_reason_clear_hint();
}
}
esp_reset_reason_t esp_reset_reason(void)
{
return s_reset_reason;
}
/* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG,
* a.k.a. RTC_ENTRY_ADDR_REG. It is safe to use this register both for the
* deep sleep wake stub entry address and for reset reason hint, since wake stub
* is only used for deep sleep reset, and in this case the reason provided by
* rtc_get_reset_reason is unambiguous.
*
* Same layout is used as for RTC_APB_FREQ_REG (a.k.a. RTC_CNTL_STORE5_REG):
* the value is replicated in low and high half-words. In addition to that,
* MSB is set to 1, which doesn't happen when RTC_CNTL_STORE6_REG contains
* deep sleep wake stub address.
*/
#define RST_REASON_BIT 0x80000000
#define RST_REASON_MASK 0x7FFF
#define RST_REASON_SHIFT 16
/* in IRAM, can be called from panic handler */
void IRAM_ATTR esp_reset_reason_set_hint(esp_reset_reason_t hint)
{
assert((hint & (~RST_REASON_MASK)) == 0);
uint32_t val = hint | (hint << RST_REASON_SHIFT) | RST_REASON_BIT;
REG_WRITE(RTC_RESET_CAUSE_REG, val);
}
/* in IRAM, can be called from panic handler */
esp_reset_reason_t IRAM_ATTR esp_reset_reason_get_hint(void)
{
uint32_t reset_reason_hint = REG_READ(RTC_RESET_CAUSE_REG);
uint32_t high = (reset_reason_hint >> RST_REASON_SHIFT) & RST_REASON_MASK;
uint32_t low = reset_reason_hint & RST_REASON_MASK;
if ((reset_reason_hint & RST_REASON_BIT) == 0 || high != low) {
return ESP_RST_UNKNOWN;
}
return (esp_reset_reason_t) low;
}
static void esp_reset_reason_clear_hint()
{
REG_WRITE(RTC_RESET_CAUSE_REG, 0);
}

View File

@ -103,11 +103,14 @@ esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void)
REG_WRITE(RTC_MEMORY_CRC_REG, stored_crc);
_lock_release(&lock_rtc_memory_crc);
if(stored_crc == calc_crc) {
return (esp_deep_sleep_wake_stub_fn_t)REG_READ(RTC_ENTRY_ADDR_REG);
} else {
if(stored_crc != calc_crc) {
return NULL;
}
esp_deep_sleep_wake_stub_fn_t stub_ptr = (esp_deep_sleep_wake_stub_fn_t) REG_READ(RTC_ENTRY_ADDR_REG);
if (!esp_ptr_executable(stub_ptr)) {
return NULL;
}
return stub_ptr;
}
void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub)
@ -178,8 +181,9 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
}
// Save current frequency and switch to XTAL
rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get();
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
rtc_cpu_freq_config_t cpu_freq_config;
rtc_clk_cpu_freq_get_config(&cpu_freq_config);
rtc_clk_cpu_freq_set_xtal();
// Configure pins for external wakeup
if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) {
@ -205,7 +209,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
uint32_t result = rtc_sleep_start(s_config.wakeup_triggers, 0);
// Restore CPU frequency
rtc_clk_cpu_freq_set(cpu_freq);
rtc_clk_cpu_freq_set_config(&cpu_freq_config);
// re-enable UART output
resume_uarts();

View File

@ -36,6 +36,7 @@
#include "freertos/task.h"
#include "freertos/xtensa_api.h"
#include "esp_heap_caps.h"
#include "esp_system_internal.h"
static const char* TAG = "system_api";
@ -333,7 +334,7 @@ void IRAM_ATTR esp_restart_noos()
DPORT_REG_WRITE(DPORT_PERIP_RST_EN_REG, 0);
// Set CPU back to XTAL source, no PLL, same as hard reset
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
rtc_clk_cpu_freq_set_xtal();
// Clear entry point for APP CPU
DPORT_REG_WRITE(DPORT_APPCPU_CTRL_D_REG, 0);

View File

@ -35,6 +35,7 @@
#include "driver/timer.h"
#include "driver/periph_ctrl.h"
#include "esp_task_wdt.h"
#include "esp_system_internal.h"
//Assertion macro where, if 'cond' is false, will exit the critical section and return 'ret'
#define ASSERT_EXIT_CRIT_RETURN(cond, ret) ({ \
@ -155,6 +156,7 @@ static void task_wdt_isr(void *arg)
if (twdt_config->panic){ //Trigger Panic if configured to do so
ets_printf("Aborting.\n");
portEXIT_CRITICAL(&twdt_spinlock);
esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
abort();
}

View File

@ -0,0 +1,27 @@
#include "unity.h"
#include "esp_attr.h"
#include "esp_log.h"
static __NOINIT_ATTR uint32_t s_noinit;
static RTC_NOINIT_ATTR uint32_t s_rtc_noinit;
static RTC_DATA_ATTR uint32_t s_rtc_data;
extern int _rtc_noinit_start;
extern int _rtc_noinit_end;
extern int _rtc_data_start;
extern int _rtc_data_end;
extern int _noinit_start;
extern int _noinit_end;
static bool data_in_segment(void *ptr, int *seg_start, int *seg_end)
{
return ((intptr_t)ptr < (intptr_t)seg_end) && \
((intptr_t)ptr >= (intptr_t)seg_start);
}
TEST_CASE("Attributes place variables into correct sections", "[ld]")
{
TEST_ASSERT(data_in_segment(&s_noinit, &_noinit_start, &_noinit_end));
TEST_ASSERT(data_in_segment(&s_rtc_noinit, &_rtc_noinit_start, &_rtc_noinit_end));
TEST_ASSERT(data_in_segment(&s_rtc_data, &_rtc_data_start, &_rtc_data_end));
}

View File

@ -1,11 +1,12 @@
#include <esp_types.h>
#include <stdio.h>
#include <stdlib.h>
#include "esp_types.h"
#include "esp_clk.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/xtensa_timer.h"
#include "soc/cpu.h"
#include "unity.h"
#include "rom/uart.h"
@ -99,49 +100,52 @@ TEST_CASE("access DPORT and APB at same time", "[esp32]")
{
dport_test_result = false;
apb_test_result = false;
printf("CPU_FREQ = %d MHz\n", rtc_clk_cpu_freq_value(rtc_clk_cpu_freq_get()) / MHZ);
printf("CPU_FREQ = %d MHz\n", esp_clk_cpu_freq());
run_tasks("accessDPORT", accessDPORT, "accessAPB", accessAPB, 10000);
}
void run_tasks_with_change_freq_cpu (rtc_cpu_freq_t cpu_freq)
void run_tasks_with_change_freq_cpu(int cpu_freq_mhz)
{
dport_test_result = false;
apb_test_result = false;
rtc_cpu_freq_t cur_freq = rtc_clk_cpu_freq_get();
uint32_t freq_before_changed = rtc_clk_cpu_freq_value(cur_freq) / MHZ;
uint32_t freq_changed = freq_before_changed;
printf("CPU_FREQ = %d MHz\n", freq_before_changed);
if (cur_freq != cpu_freq) {
uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
rtc_clk_cpu_freq_set(cpu_freq);
const int uart_num = CONFIG_CONSOLE_UART_NUM;
const int uart_baud = CONFIG_CONSOLE_UART_BAUDRATE;
uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud);
freq_changed = rtc_clk_cpu_freq_value(rtc_clk_cpu_freq_get()) / MHZ;
printf("CPU_FREQ switching to %d MHz\n", freq_changed);
}
run_tasks("accessDPORT", accessDPORT, "accessAPB", accessAPB, 10000 / ((freq_before_changed <= freq_changed) ? 1 : (freq_before_changed / freq_changed)));
// return old freq.
uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
rtc_clk_cpu_freq_set(cur_freq);
const int uart_num = CONFIG_CONSOLE_UART_NUM;
const int uart_baud = CONFIG_CONSOLE_UART_BAUDRATE;
dport_test_result = false;
apb_test_result = false;
rtc_cpu_freq_config_t old_config;
rtc_clk_cpu_freq_get_config(&old_config);
printf("CPU_FREQ = %d MHz\n", old_config.freq_mhz);
if (cpu_freq_mhz != old_config.freq_mhz) {
rtc_cpu_freq_config_t new_config;
bool res = rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &new_config);
assert(res && "invalid frequency value");
uart_tx_wait_idle(uart_num);
rtc_clk_cpu_freq_set_config(&new_config);
uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud);
/* adjust RTOS ticks */
_xt_tick_divisor = cpu_freq_mhz * 1000000 / XT_TICK_PER_SEC;
vTaskDelay(2);
printf("CPU_FREQ switched to %d MHz\n", cpu_freq_mhz);
}
run_tasks("accessDPORT", accessDPORT, "accessAPB", accessAPB, 10000);
// return old freq.
uart_tx_wait_idle(uart_num);
rtc_clk_cpu_freq_set_config(&old_config);
uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud);
_xt_tick_divisor = old_config.freq_mhz * 1000000 / XT_TICK_PER_SEC;
}
TEST_CASE("access DPORT and APB at same time (Freq CPU and APB = 80 MHz)", "[esp32] [ignore]")
{
run_tasks_with_change_freq_cpu(RTC_CPU_FREQ_80M);
run_tasks_with_change_freq_cpu(80);
}
TEST_CASE("access DPORT and APB at same time (Freq CPU and APB = 40 MHz (XTAL))", "[esp32]")
{
run_tasks_with_change_freq_cpu(RTC_CPU_FREQ_XTAL);
run_tasks_with_change_freq_cpu((int) rtc_clk_xtal_freq_get());
}
static uint32_t stall_other_cpu_counter;

View File

@ -1,9 +0,0 @@
#include "unity.h"
#include "esp_system.h"
#include "string.h"
TEST_CASE("make exception", "[restart][reset=StoreProhibited,SW_CPU_RESET]")
{
*(int *) NULL = 0;
}

View File

@ -1,20 +0,0 @@
/*
Tests for the interrupt watchdog
*/
#include <esp_types.h>
#include <stdio.h>
#include "rom/ets_sys.h"
#include "unity.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
TEST_CASE("Int wdt test", "[esp32][reset=Interrupt wdt timeout on CPU0,SW_CPU_RESET]")
{
portENTER_CRITICAL_NESTED();
while(1);
}

View File

@ -1,123 +0,0 @@
#include "unity.h"
#include "esp_system.h"
#include "rom/rtc.h"
#include "esp_log.h"
// This is a test sequence to test behavior of .rtc_noinit and .noinit sections.
// The values placed into .rtc_noinit section go to RTC SLOW Memory segment and
// keep their value after reset and deep sleep. Use new added attribute macro
// RTC_NOINIT_ATTR for this behavior. The second macro - __NOINIT_ATTR places value
// into .noinit section which goes to SRAM and will not be initialized after reset.
#define RTC_NOINIT_PATTERN 0xAAAAAAAA
#define _NOINIT_PATTERN 0x55555555
static __NOINIT_ATTR uint32_t noinit_data;
static RTC_NOINIT_ATTR uint32_t rtc_noinit_data;
extern int _rtc_noinit_start;
extern int _rtc_noinit_end;
extern int _noinit_start;
extern int _noinit_end;
// Pointers to the values
uint32_t *noinit_val_addr = (uint32_t*)&noinit_data;
uint32_t *rtc_noinit_val_addr = (uint32_t*)&rtc_noinit_data;
static const char* tag = "noinit_UnitTestMain";
static esp_err_t check_data_seg(uint32_t *value_address, \
uint32_t *seg_start, uint32_t *seg_end)
{
esp_err_t result = ESP_FAIL;
if (((uint32_t)value_address <= (uint32_t)seg_end) && \
((uint32_t)value_address >= (uint32_t)seg_start)){
result = ESP_OK;
}
return result;
}
static void setup_attributes(void)
{
rtc_noinit_data = RTC_NOINIT_PATTERN;
noinit_data = _NOINIT_PATTERN;
}
static void init_attributes(void)
{
setup_attributes();
printf("noinit_data = 0x%X \n", (uint32_t)*noinit_val_addr);
printf("rtc_noinit_data = 0x%X \n", (uint32_t)*rtc_noinit_val_addr);
TEST_ASSERT(*noinit_val_addr == noinit_data);
TEST_ASSERT(*rtc_noinit_val_addr == rtc_noinit_data);
}
static void reset_reason_power_on(void)
{
printf("This test case checks behavior of noinit variables POWERON_RESET sequence. \n");
RESET_REASON reason = rtc_get_reset_reason(0);
ESP_LOGI(tag, "POWERON_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
(uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
TEST_ASSERT((reason == POWERON_RESET) || (reason == RTCWDT_RTC_RESET));
init_attributes();
TEST_ASSERT(check_data_seg(noinit_val_addr, \
(uint32_t*)&_noinit_start, \
(uint32_t*)&_noinit_end) == ESP_OK);
TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
(uint32_t*)&_rtc_noinit_start, \
(uint32_t*)&_rtc_noinit_end) == ESP_OK);
TEST_ASSERT(_NOINIT_PATTERN == *noinit_val_addr);
TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
printf("Next test case will check SOFTWARE_RESET behavior. \n");
esp_restart();
}
static void reset_reason_sw_reset(void)
{
printf("This test case checks behavior of noinit variables after software reset sequence. \n");
RESET_REASON reason = rtc_get_reset_reason(0);
ESP_LOGI(tag, "SW_CPU_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
(uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
TEST_ASSERT(reason == SW_CPU_RESET);
TEST_ASSERT(check_data_seg(noinit_val_addr, \
(uint32_t*)&_noinit_start, \
(uint32_t*)&_noinit_end) == ESP_OK);
TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
(uint32_t*)&_rtc_noinit_start, \
(uint32_t*)&_rtc_noinit_end) == ESP_OK);
// The ROM bootloader behavior may apply to this assert.
// TEST_ASSERT(0x55555555 == *noinit_val_addr);
TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
printf("Go to deep sleep to check DEEP_SLEEP_RESET behavior. \n");
esp_sleep_enable_timer_wakeup(2000000);
esp_deep_sleep_start();
}
static void reset_reason_deep_sleep(void)
{
printf("This test case checks behavior of noinit variables after deep sleep reset. \n");
RESET_REASON reason = rtc_get_reset_reason(0);
ESP_LOGI(tag, "DEEP_SLEEP_RESET reset values = (0x%X), (0x%X), reset reason=(%d)\n", \
(uint32_t)*noinit_val_addr, (uint32_t)*rtc_noinit_val_addr, (uint16_t)reason);
TEST_ASSERT(reason == DEEPSLEEP_RESET);
TEST_ASSERT(check_data_seg(noinit_val_addr, \
(uint32_t*)&_noinit_start, \
(uint32_t*)&_noinit_end) == ESP_OK);
TEST_ASSERT(check_data_seg(rtc_noinit_val_addr, \
(uint32_t*)&_rtc_noinit_start, \
(uint32_t*)&_rtc_noinit_end) == ESP_OK);
TEST_ASSERT(RTC_NOINIT_PATTERN == *rtc_noinit_val_addr);
printf("The noinit test cases are done.. \n");
}
// The lines below are required to suppress GCC warnings about casting of function pointers
// in unity macro expansion. These warnings may be treated as errors during automated test.
#pragma GCC diagnostic push // required for GCC
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
// The multiple stages test case to check values after certain reset reason
TEST_CASE_MULTIPLE_STAGES("NOINIT attributes behavior",
"[restart][reset=SW_CPU_RESET, DEEPSLEEP_RESET]",
reset_reason_power_on, reset_reason_sw_reset, reset_reason_deep_sleep);
#pragma GCC diagnostic pop // require GCC

View File

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/param.h>
#include "unity.h"
#include "esp_pm.h"
#include "esp_clk.h"
@ -25,19 +26,17 @@ TEST_CASE("Can dump power management lock stats", "[pm]")
static void switch_freq(int mhz)
{
rtc_cpu_freq_t max_freq;
assert(rtc_clk_cpu_freq_from_mhz(mhz, &max_freq));
int xtal_freq = rtc_clk_xtal_freq_get();
esp_pm_config_esp32_t pm_config = {
.max_cpu_freq = max_freq,
.min_cpu_freq = RTC_CPU_FREQ_XTAL,
.max_freq_mhz = mhz,
.min_freq_mhz = MIN(mhz, xtal_freq),
};
ESP_ERROR_CHECK( esp_pm_configure(&pm_config) );
printf("Waiting for frequency to be set to %d (%d MHz)...\n", max_freq, mhz);
printf("Waiting for frequency to be set to %d MHz...\n", mhz);
while (esp_clk_cpu_freq() / 1000000 != mhz) {
vTaskDelay(pdMS_TO_TICKS(1000));
printf("Frequency is %d MHz\n", esp_clk_cpu_freq());
vTaskDelay(pdMS_TO_TICKS(200));
printf("Frequency is %d MHz\n", esp_clk_cpu_freq() / 1000000);
}
printf("Frequency is set to %d MHz\n", mhz);
}
TEST_CASE("Can switch frequency using esp_pm_configure", "[pm]")
@ -52,6 +51,10 @@ TEST_CASE("Can switch frequency using esp_pm_configure", "[pm]")
switch_freq(240);
switch_freq(40);
switch_freq(80);
switch_freq(10);
switch_freq(80);
switch_freq(20);
switch_freq(40);
switch_freq(orig_freq_mhz);
}

View File

@ -0,0 +1,211 @@
#include "unity.h"
#include "esp_system.h"
#include "esp_task_wdt.h"
#include "esp_attr.h"
#include "soc/rtc_cntl_reg.h"
#define RTC_BSS_ATTR __attribute__((section(".rtc.bss")))
static __NOINIT_ATTR uint32_t s_noinit_val;
static RTC_NOINIT_ATTR uint32_t s_rtc_noinit_val;
static RTC_DATA_ATTR uint32_t s_rtc_data_val;
static RTC_BSS_ATTR uint32_t s_rtc_bss_val;
#define CHECK_VALUE 0x89abcdef
static void setup_values()
{
s_noinit_val = CHECK_VALUE;
s_rtc_noinit_val = CHECK_VALUE;
s_rtc_data_val = CHECK_VALUE;
s_rtc_bss_val = CHECK_VALUE;
}
/* This test needs special test runners: rev1 silicon, and SPI flash with
* fast start-up time. Otherwise reset reason will be RTCWDT_RESET.
*/
TEST_CASE("reset reason ESP_RST_POWERON", "[reset][ignore]")
{
TEST_ASSERT_EQUAL(ESP_RST_POWERON, esp_reset_reason());
}
static void do_deep_sleep()
{
setup_values();
esp_sleep_enable_timer_wakeup(10000);
esp_deep_sleep_start();
}
static void check_reset_reason_deep_sleep()
{
TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_DEEPSLEEP", "[reset_reason][reset=DEEPSLEEP_RESET]",
do_deep_sleep,
check_reset_reason_deep_sleep);
static void do_exception()
{
setup_values();
*(int*) (0x40000001) = 0;
}
static void do_abort()
{
setup_values();
abort();
}
static void check_reset_reason_panic()
{
TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after exception", "[reset_reason][reset=LoadStoreError,SW_CPU_RESET]",
do_exception,
check_reset_reason_panic);
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after abort", "[reset_reason][reset=abort,SW_CPU_RESET]",
do_abort,
check_reset_reason_panic);
static void do_restart()
{
setup_values();
esp_restart();
}
#if portNUM_PROCESSORS > 1
static void do_restart_from_app_cpu()
{
setup_values();
xTaskCreatePinnedToCore((TaskFunction_t) &do_restart, "restart", 2048, NULL, 5, NULL, 1);
vTaskDelay(2);
}
#endif
static void check_reset_reason_sw()
{
TEST_ASSERT_EQUAL(ESP_RST_SW, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart", "[reset_reason][reset=SW_CPU_RESET]",
do_restart,
check_reset_reason_sw);
#if portNUM_PROCESSORS > 1
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart from APP CPU", "[reset_reason][reset=SW_CPU_RESET]",
do_restart_from_app_cpu,
check_reset_reason_sw);
#endif
static void do_int_wdt()
{
portENTER_CRITICAL_NESTED();
while(1);
}
static void do_int_wdt_hw()
{
XTOS_SET_INTLEVEL(XCHAL_NMILEVEL);
while(1);
}
static void check_reset_reason_int_wdt()
{
TEST_ASSERT_EQUAL(ESP_RST_INT_WDT, esp_reset_reason());
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog (panic)",
"[reset_reason][reset=Interrupt wdt timeout on CPU0,SW_CPU_RESET]",
do_int_wdt,
check_reset_reason_int_wdt);
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog (hw)",
"[reset_reason][reset=TG1WDT_SYS_RESET]",
do_int_wdt_hw,
check_reset_reason_int_wdt);
static void do_task_wdt()
{
setup_values();
esp_task_wdt_init(1, true);
esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(0));
while(1);
}
static void check_reset_reason_task_wdt()
{
TEST_ASSERT_EQUAL(ESP_RST_TASK_WDT, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_TASK_WDT after task watchdog",
"[reset_reason][reset=abort,SW_CPU_RESET]",
do_task_wdt,
check_reset_reason_task_wdt);
static void do_rtc_wdt()
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM);
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, 10000);
REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
while(1);
}
static void check_reset_reason_any_wdt()
{
TEST_ASSERT_EQUAL(ESP_RST_WDT, esp_reset_reason());
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_WDT after RTC watchdog",
"[reset_reason][reset=RTCWDT_RTC_RESET]",
do_rtc_wdt,
check_reset_reason_any_wdt);
static void do_brownout()
{
setup_values();
printf("Manual test: lower the supply voltage to cause brownout\n");
vTaskSuspend(NULL);
}
static void check_reset_reason_brownout()
{
TEST_ASSERT_EQUAL(ESP_RST_BROWNOUT, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_noinit_val);
TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_data_val);
TEST_ASSERT_EQUAL_HEX32(0, s_rtc_bss_val);
}
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_BROWNOUT after brownout event",
"[reset_reason][ignore][reset=SW_CPU_RESET]",
do_brownout,
check_reset_reason_brownout);
/* Not tested here: ESP_RST_SDIO */

View File

@ -1,25 +0,0 @@
#include "unity.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
TEST_CASE("restart from PRO CPU", "[restart][reset=SW_CPU_RESET]")
{
esp_restart();
}
static void restart_task(void *arg)
{
esp_restart();
}
#ifndef CONFIG_FREERTOS_UNICORE
TEST_CASE("restart from APP CPU", "[restart][reset=SW_CPU_RESET]")
{
xTaskCreatePinnedToCore(&restart_task, "restart", 2048, NULL, 5, NULL, 1);
while (true) {
;
}
}
#endif

View File

@ -177,13 +177,16 @@ TEST_CASE("light sleep and frequency switching", "[deepsleep]")
uart_div_modify(CONFIG_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
#endif
rtc_cpu_freq_config_t config_xtal, config_default;
rtc_clk_cpu_freq_get_config(&config_default);
rtc_clk_cpu_freq_mhz_to_config((int) rtc_clk_xtal_freq_get(), &config_xtal);
esp_sleep_enable_timer_wakeup(1000);
rtc_cpu_freq_t default_freq = rtc_clk_cpu_freq_get();
for (int i = 0; i < 1000; ++i) {
if (i % 2 == 0) {
rtc_clk_cpu_freq_set_fast(RTC_CPU_FREQ_XTAL);
rtc_clk_cpu_freq_set_config_fast(&config_xtal);
} else {
rtc_clk_cpu_freq_set_fast(default_freq);
rtc_clk_cpu_freq_set_config_fast(&config_default);
}
printf("%d\n", i);
fflush(stdout);
@ -199,6 +202,74 @@ TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][re
}
#endif
static void do_deep_sleep()
{
esp_sleep_enable_timer_wakeup(100000);
esp_deep_sleep_start();
}
static void check_sleep_reset_and_sleep()
{
TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason());
esp_sleep_enable_timer_wakeup(100000);
esp_deep_sleep_start();
}
static void check_sleep_reset()
{
TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason());
}
TEST_CASE_MULTIPLE_STAGES("enter deep sleep more than once", "[deepsleep][reset=DEEPSLEEP_RESET,DEEPSLEEP_RESET,DEEPSLEEP_RESET]",
do_deep_sleep,
check_sleep_reset_and_sleep,
check_sleep_reset_and_sleep,
check_sleep_reset);
static void do_abort()
{
abort();
}
static void check_abort_reset_and_sleep()
{
TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason());
esp_sleep_enable_timer_wakeup(100000);
esp_deep_sleep_start();
}
TEST_CASE_MULTIPLE_STAGES("enter deep sleep after abort", "[deepsleep][reset=abort,SW_CPU_RESET,DEEPSLEEP_RESET]",
do_abort,
check_abort_reset_and_sleep,
check_sleep_reset);
static RTC_DATA_ATTR uint32_t s_wake_stub_var;
static RTC_IRAM_ATTR void wake_stub()
{
esp_default_wake_deep_sleep();
s_wake_stub_var = (uint32_t) &wake_stub;
}
static void prepare_wake_stub()
{
esp_set_deep_sleep_wake_stub(&wake_stub);
esp_sleep_enable_timer_wakeup(100000);
esp_deep_sleep_start();
}
static void check_wake_stub()
{
TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason());
TEST_ASSERT_EQUAL_HEX32((uint32_t) &wake_stub, s_wake_stub_var);
/* ROM code clears wake stub entry address */
TEST_ASSERT_NULL(esp_get_deep_sleep_wake_stub());
}
TEST_CASE_MULTIPLE_STAGES("can set sleep wake stub", "[deepsleep][reset=DEEPSLEEP_RESET]",
prepare_wake_stub,
check_wake_stub);
TEST_CASE("wake up using ext0 (13 high)", "[deepsleep][ignore]")
{

View File

@ -3,6 +3,6 @@ set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "lib/include")
set(COMPONENT_REQUIRES "nghttp")
set(COMPONENT_PRIV_REQUIRES "mbedtls" "lwip")
set(COMPONENT_PRIV_REQUIRES "mbedtls" "lwip" "esp-tls")
register_component()

View File

@ -878,7 +878,7 @@ esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len)
return ESP_ERR_HTTP_INVALID_TRANSPORT;
}
if (transport_connect(client->transport, client->connection_info.host, client->connection_info.port, client->timeout_ms) < 0) {
ESP_LOGE(TAG, "Connection failed, sock < 0");
ESP_LOGE(TAG, "Connection failed");
return ESP_ERR_HTTP_CONNECT;
}
http_dispatch_event(client, HTTP_EVENT_ON_CONNECTED, NULL, 0);
@ -932,10 +932,17 @@ esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len)
}
client->request->buffer->data[wlen] = 0;
ESP_LOGD(TAG, "Write header[%d]: %s", header_index, client->request->buffer->data);
if (transport_write(client->transport, client->request->buffer->data, wlen, client->timeout_ms) <= 0) {
ESP_LOGE(TAG, "Error write request");
esp_http_client_close(client);
return ESP_ERR_HTTP_WRITE_DATA;
int widx = 0, wret = 0;
while (wlen > 0) {
wret = transport_write(client->transport, client->request->buffer->data + widx, wlen, client->timeout_ms);
if (wret <= 0) {
ESP_LOGE(TAG, "Error write request");
esp_http_client_close(client);
return ESP_ERR_HTTP_WRITE_DATA;
}
widx += wret;
wlen -= wret;
}
wlen = client->buffer_size;
}
@ -949,14 +956,10 @@ int esp_http_client_write(esp_http_client_handle_t client, const char *buffer, i
if (client->state < HTTP_STATE_REQ_COMPLETE_HEADER) {
return ESP_FAIL;
}
int need_write;
int wlen = 0, widx = 0;
while (len > 0) {
need_write = len;
if (need_write > client->buffer_size) {
need_write = client->buffer_size;
}
wlen = transport_write(client->transport, buffer + widx, need_write, client->timeout_ms);
wlen = transport_write(client->transport, buffer + widx, len, client->timeout_ms);
if (wlen <= 0) {
return wlen;
}

View File

@ -17,22 +17,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/esp_debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
#include "esp_tls.h"
#include "esp_log.h"
#include "esp_system.h"
@ -45,12 +30,7 @@ static const char *TAG = "TRANS_SSL";
* mbedtls specific transport data
*/
typedef struct {
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ctx;
mbedtls_x509_crt cacert;
mbedtls_ssl_config conf;
mbedtls_net_context client_fd;
esp_tls_t *tls;
void *cert_pem_data;
int cert_pem_len;
bool ssl_initialized;
@ -61,108 +41,21 @@ static int ssl_close(transport_handle_t t);
static int ssl_connect(transport_handle_t t, const char *host, int port, int timeout_ms)
{
int ret = -1, flags;
struct timeval tv;
transport_ssl_t *ssl = transport_get_context_data(t);
if (!ssl) {
esp_tls_cfg_t cfg = { 0 };
if (ssl->cert_pem_data) {
ssl->verify_server = true;
cfg.cacert_pem_buf = ssl->cert_pem_data;
cfg.cacert_pem_bytes = ssl->cert_pem_len + 1;
}
cfg.timeout_ms = timeout_ms;
ssl->ssl_initialized = true;
ssl->tls = esp_tls_conn_new(host, strlen(host), port, &cfg);
if (!ssl->tls) {
ESP_LOGE(TAG, "Failed to open a new connection");
return -1;
}
ssl->ssl_initialized = true;
mbedtls_ssl_init(&ssl->ctx);
mbedtls_ctr_drbg_init(&ssl->ctr_drbg);
mbedtls_ssl_config_init(&ssl->conf);
mbedtls_entropy_init(&ssl->entropy);
if ((ret = mbedtls_ssl_config_defaults(&ssl->conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
goto exit;
}
if ((ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, &ssl->entropy, NULL, 0)) != 0) {
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
goto exit;
}
if (ssl->cert_pem_data) {
mbedtls_x509_crt_init(&ssl->cacert);
ssl->verify_server = true;
if ((ret = mbedtls_x509_crt_parse(&ssl->cacert, ssl->cert_pem_data, ssl->cert_pem_len + 1)) < 0) {
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\nDATA=%s,len=%d", -ret, (char*)ssl->cert_pem_data, ssl->cert_pem_len);
goto exit;
}
mbedtls_ssl_conf_ca_chain(&ssl->conf, &ssl->cacert, NULL);
mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
if ((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
goto exit;
}
} else {
mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_NONE);
}
mbedtls_ssl_conf_rng(&ssl->conf, mbedtls_ctr_drbg_random, &ssl->ctr_drbg);
#ifdef CONFIG_MBEDTLS_DEBUG
mbedtls_esp_enable_debug_log(&ssl->conf, 4);
#endif
if ((ret = mbedtls_ssl_setup(&ssl->ctx, &ssl->conf)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
goto exit;
}
mbedtls_net_init(&ssl->client_fd);
http_utils_ms_to_timeval(timeout_ms, &tv);
setsockopt(ssl->client_fd.fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
ESP_LOGD(TAG, "Connect to %s:%d", host, port);
char port_str[8] = {0};
sprintf(port_str, "%d", port);
if ((ret = mbedtls_net_connect(&ssl->client_fd, host, port_str, MBEDTLS_NET_PROTO_TCP)) != 0) {
ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
goto exit;
}
mbedtls_ssl_set_bio(&ssl->ctx, &ssl->client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
if((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) {
ESP_LOGE(TAG, " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
goto exit;
}
ESP_LOGD(TAG, "Performing the SSL/TLS handshake...");
while ((ret = mbedtls_ssl_handshake(&ssl->ctx)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
goto exit;
}
}
ESP_LOGD(TAG, "Verifying peer X.509 certificate...");
if ((flags = mbedtls_ssl_get_verify_result(&ssl->ctx)) != 0) {
/* In real life, we probably want to close connection if ret != 0 */
ESP_LOGW(TAG, "Failed to verify peer certificate!");
if (ssl->cert_pem_data) {
goto exit;
}
} else {
ESP_LOGD(TAG, "Certificate verified.");
}
ESP_LOGD(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl->ctx));
return ret;
exit:
ssl_close(t);
return ret;
return 0;
}
static int ssl_poll_read(transport_handle_t t, int timeout_ms)
@ -170,11 +63,11 @@ static int ssl_poll_read(transport_handle_t t, int timeout_ms)
transport_ssl_t *ssl = transport_get_context_data(t);
fd_set readset;
FD_ZERO(&readset);
FD_SET(ssl->client_fd.fd, &readset);
FD_SET(ssl->tls->sockfd, &readset);
struct timeval timeout;
http_utils_ms_to_timeval(timeout_ms, &timeout);
return select(ssl->client_fd.fd + 1, &readset, NULL, NULL, &timeout);
return select(ssl->tls->sockfd + 1, &readset, NULL, NULL, &timeout);
}
static int ssl_poll_write(transport_handle_t t, int timeout_ms)
@ -182,10 +75,10 @@ static int ssl_poll_write(transport_handle_t t, int timeout_ms)
transport_ssl_t *ssl = transport_get_context_data(t);
fd_set writeset;
FD_ZERO(&writeset);
FD_SET(ssl->client_fd.fd, &writeset);
FD_SET(ssl->tls->sockfd, &writeset);
struct timeval timeout;
http_utils_ms_to_timeval(timeout_ms, &timeout);
return select(ssl->client_fd.fd + 1, NULL, &writeset, NULL, &timeout);
return select(ssl->tls->sockfd + 1, NULL, &writeset, NULL, &timeout);
}
static int ssl_write(transport_handle_t t, const char *buffer, int len, int timeout_ms)
@ -194,10 +87,10 @@ static int ssl_write(transport_handle_t t, const char *buffer, int len, int time
transport_ssl_t *ssl = transport_get_context_data(t);
if ((poll = transport_poll_write(t, timeout_ms)) <= 0) {
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->client_fd.fd, timeout_ms);
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->tls->sockfd, timeout_ms);
return poll;
}
ret = mbedtls_ssl_write(&ssl->ctx, (const unsigned char *) buffer, len);
ret = esp_tls_conn_write(ssl->tls, (const unsigned char *) buffer, len);
if (ret <= 0) {
ESP_LOGE(TAG, "mbedtls_ssl_write error, errno=%s", strerror(errno));
}
@ -206,14 +99,18 @@ static int ssl_write(transport_handle_t t, const char *buffer, int len, int time
static int ssl_read(transport_handle_t t, char *buffer, int len, int timeout_ms)
{
int poll = -1, ret;
int poll, ret;
transport_ssl_t *ssl = transport_get_context_data(t);
if (mbedtls_ssl_get_bytes_avail(&ssl->ctx) <= 0) {
if (esp_tls_get_bytes_avail(ssl->tls) <= 0) {
if ((poll = transport_poll_read(t, timeout_ms)) <= 0) {
return poll;
}
}
ret = mbedtls_ssl_read(&ssl->ctx, (unsigned char *)buffer, len);
ret = esp_tls_conn_read(ssl->tls, (unsigned char *)buffer, len);
if (ret <= 0) {
ESP_LOGE(TAG, "mbedtls_ssl_read error, errno=%s", strerror(errno));
}
return ret;
}
@ -222,17 +119,7 @@ static int ssl_close(transport_handle_t t)
int ret = -1;
transport_ssl_t *ssl = transport_get_context_data(t);
if (ssl->ssl_initialized) {
ESP_LOGD(TAG, "Cleanup mbedtls");
mbedtls_ssl_close_notify(&ssl->ctx);
mbedtls_ssl_session_reset(&ssl->ctx);
mbedtls_net_free(&ssl->client_fd);
mbedtls_ssl_config_free(&ssl->conf);
if (ssl->verify_server) {
mbedtls_x509_crt_free(&ssl->cacert);
}
mbedtls_ctr_drbg_free(&ssl->ctr_drbg);
mbedtls_entropy_free(&ssl->entropy);
mbedtls_ssl_free(&ssl->ctx);
esp_tls_conn_delete(ssl->tls);
ssl->ssl_initialized = false;
ssl->verify_server = false;
}
@ -261,7 +148,6 @@ transport_handle_t transport_ssl_init()
transport_handle_t t = transport_init();
transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t));
HTTP_MEM_CHECK(TAG, ssl, return NULL);
mbedtls_net_init(&ssl->client_fd);
transport_set_context_data(t, ssl);
transport_set_func(t, ssl_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy);
return t;

View File

@ -55,17 +55,17 @@ endif
# non-secure boot (or bootloader), both these files are the same
APP_BIN_UNSIGNED ?= $(APP_BIN)
$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC)
$(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
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
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:
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: $(call prereq_if_explicit,%flash)
simple_monitor: check_python_dependencies $(call prereq_if_explicit,%flash)
$(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: $(call prereq_if_explicit,%flash)
monitor: check_python_dependencies $(call prereq_if_explicit,%flash)
$(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

@ -26,15 +26,23 @@ config EMAC_L2_TO_L3_RX_BUF_MODE
If this options is selected, a copy of each received buffer will be created when
passing it from the Ethernet MAC (L2) to the IP stack (L3). Otherwise, IP stack
will receive pointers to the DMA buffers used by Ethernet MAC.
When Ethernet MAC doesn't have any unused buffers left, it will drop incomming
packets (flow control may help with this problem, to some extent).
The buffers for the IP stack are allocated from the heap, so the total number of
receive buffers is limited by the available heap size, if this option is selected.
If unsure, choose n.
config EMAC_CHECK_LINK_PERIOD_MS
int "Period(ms) of checking Ethernet linkup status"
range 1000 5000
default 2000
help
The emac driver uses an internal timer to check the ethernet linkup
status. Here you should choose a valid the interval time.
config EMAC_TASK_PRIORITY
int "EMAC_TASK_PRIORITY"
default 20

View File

@ -98,7 +98,6 @@ void emac_dma_init(void)
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_FWD_UNDER_GF);
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_OPT_SECOND_FRAME);
REG_SET_FIELD(EMAC_DMABUSMODE_REG, EMAC_PROG_BURST_LEN, 4);
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_DMAOPERATION_MODE_REG);
}
void emac_mac_enable_txrx(void)

View File

@ -31,13 +31,13 @@ struct dma_desc {
uint32_t desc3;
};
struct dma_extended_desc {
typedef struct dma_extended_desc {
struct dma_desc basic;
uint32_t desc4;
uint32_t desc5;
uint32_t desc6;
uint32_t desc7;
};
}dma_extended_desc_t;
void emac_enable_clk(bool enable);
void emac_reset(void);
@ -54,54 +54,54 @@ void emac_enable_flowctrl(void);
void emac_disable_flowctrl(void);
void emac_mac_enable_txrx(void);
uint32_t inline emac_read_tx_cur_reg(void)
static inline uint32_t emac_read_tx_cur_reg(void)
{
return REG_READ(EMAC_DMATXCURRDESC_REG);
}
uint32_t inline emac_read_rx_cur_reg(void)
static inline uint32_t emac_read_rx_cur_reg(void)
{
return REG_READ(EMAC_DMARXCURRDESC_REG);
}
void inline emac_poll_tx_cmd(void)
static inline void emac_poll_tx_cmd(void)
{
//write any to wake up dma
REG_WRITE(EMAC_DMATXPOLLDEMAND_REG, 1);
}
void inline emac_poll_rx_cmd(void)
static inline void emac_poll_rx_cmd(void)
{
//write any to wake up dma
REG_WRITE(EMAC_DMARXPOLLDEMAND_REG, 1);
}
void inline emac_disable_rx_intr(void)
static inline void emac_disable_rx_intr(void)
{
REG_CLR_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RIE);
}
void inline emac_enable_rx_intr(void)
static inline void emac_enable_rx_intr(void)
{
REG_SET_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RIE);
}
void inline emac_disable_rx_unavail_intr(void)
static inline void emac_disable_rx_unavail_intr(void)
{
REG_CLR_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RBUE);
}
void inline emac_enable_rx_unavail_intr(void)
static inline void emac_enable_rx_unavail_intr(void)
{
REG_SET_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RBUE);
}
void IRAM_ATTR inline emac_send_pause_frame_enable(void)
static inline void IRAM_ATTR emac_send_pause_frame_enable(void)
{
REG_SET_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL);
}
void inline emac_send_pause_zero_frame_enable(void)
static inline void emac_send_pause_zero_frame_enable(void)
{
REG_CLR_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL);
}

View File

@ -13,6 +13,7 @@
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rom/ets_sys.h"
@ -58,15 +59,15 @@
static struct emac_config_data emac_config;
static uint8_t emac_dma_rx_chain_buf[sizeof(struct dma_extended_desc) * DMA_RX_BUF_NUM];
static uint8_t emac_dma_tx_chain_buf[sizeof(struct dma_extended_desc) * DMA_TX_BUF_NUM];
static uint8_t emac_dma_rx_buf[DMA_RX_BUF_SIZE * DMA_RX_BUF_NUM];
static uint8_t emac_dma_tx_buf[DMA_TX_BUF_SIZE * DMA_TX_BUF_NUM];
static dma_extended_desc_t *emac_dma_rx_chain_buf[DMA_RX_BUF_NUM];
static dma_extended_desc_t *emac_dma_tx_chain_buf[DMA_TX_BUF_NUM];
static uint8_t *emac_dma_rx_buf[DMA_RX_BUF_NUM];
static uint8_t *emac_dma_tx_buf[DMA_TX_BUF_NUM];
static SemaphoreHandle_t emac_g_sem;
static SemaphoreHandle_t emac_g_sem = NULL;
static portMUX_TYPE g_emac_mux = portMUX_INITIALIZER_UNLOCKED;
static xTaskHandle emac_task_hdl;
static xQueueHandle emac_xqueue;
static xTaskHandle emac_task_hdl = NULL;
static xQueueHandle emac_xqueue = NULL;
static uint8_t emac_sig_cnt[EMAC_SIG_MAX] = {0};
static TimerHandle_t emac_timer = NULL;
static SemaphoreHandle_t emac_rx_xMutex = NULL;
@ -92,19 +93,23 @@ void esp_eth_get_mac(uint8_t mac[6])
esp_err_t esp_eth_set_mac(const uint8_t mac[6])
{
if((mac[0] & 0x01) == 0) {
memcpy(&(emac_config.macaddr[0]),mac, 6);
if ((mac[0] & 0x01) == 0) {
memcpy(&(emac_config.macaddr[0]), mac, 6);
return ESP_OK;
} else {
return ESP_ERR_INVALID_MAC;
}
}
static void emac_setup_tx_desc(struct dma_extended_desc *tx_desc , uint32_t size)
static void emac_setup_tx_desc(struct dma_extended_desc *tx_desc, uint32_t size)
{
tx_desc->basic.desc1 = size & 0xfff;
tx_desc->basic.desc0 = EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN;
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN;
tx_desc->basic.desc0 = EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT |
EMAC_DESC_FIRST_SEGMENT |
EMAC_DESC_SECOND_ADDR_CHAIN;
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL |
EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT |
EMAC_DESC_SECOND_ADDR_CHAIN;
}
static void emac_clean_tx_desc(struct dma_extended_desc *tx_desc)
@ -113,7 +118,8 @@ static void emac_clean_tx_desc(struct dma_extended_desc *tx_desc)
tx_desc->basic.desc0 = 0;
}
static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc , uint32_t buf_ptr)
static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc,
uint32_t buf_ptr)
{
if (buf_ptr != 0) {
rx_desc->basic.desc2 = buf_ptr;
@ -133,23 +139,34 @@ static void emac_set_rx_base_reg(void)
}
/*
* dirty_rx indicates the hardware has been fed with data packets and is the first node software needs to handle;
* dirty_rx indicates the hardware has been fed with data packets and is the
* first node software needs to handle;
*
* cur_rx indicates the completion of software handling and is the last node hardware could use;
* cur_rx indicates the completion of software handling and is the last node
* hardware could use;
*
* cnt_rx is to count the numbers of packets handled by software, passed to protocol stack and not been freed.
* cnt_rx is to count the numbers of packets handled by software, passed to
* protocol stack and not been freed.
*
* (1) Initializing the Linked List. Connect the numerable nodes to a circular linked list, appoint one of the nodes as the head node, mark* the dirty_rx and cur_rx into the node, and mount the node on the hardware base address. Initialize cnt_rx into 0.
* (1) Initializing the Linked List. Connect the numerable nodes to a circular
* linked list, appoint one of the nodes as the head node, mark* the dirty_rx
* and cur_rx into the node, and mount the node on the hardware base address.
* Initialize cnt_rx into 0.
*
* (2) When hardware receives packets, nodes of linked lists will be fed with data packets from the base address by turns, marks the node
* (2) When hardware receives packets, nodes of linked lists will be fed with
* data packets from the base address by turns, marks the node
* of linked lists as HARDWARE UNUSABLE and reports interrupts.
*
* (3) When the software receives the interrupts, it will handle the linked lists by turns from dirty_rx, send data packets to protocol
* (3) When the software receives the interrupts, it will handle the linked
* lists by turns from dirty_rx, send data packets to protocol
* stack. dirty_rx will deviate backwards by turns and cnt_rx will by turns ++.
*
* (4) After the protocol stack handles all the data and calls the free function, it will deviate backwards by turns from cur_rx, mark the * node of linked lists as HARDWARE USABLE and cnt_rx will by turns --.
* (4) After the protocol stack handles all the data and calls the free function,
* it will deviate backwards by turns from cur_rx, mark the * node of linked
* lists as HARDWARE USABLE and cnt_rx will by turns --.
*
* (5) Cycle from Step 2 to Step 4 without break and build up circular linked list handling.
* (5) Cycle from Step 2 to Step 4 without break and build up circular linked
* list handling.
*/
static void emac_reset_dma_chain(void)
{
@ -165,48 +182,46 @@ static void emac_reset_dma_chain(void)
static void emac_init_dma_chain(void)
{
int i;
uint32_t dma_phy;
struct dma_extended_desc *p = NULL;
dma_extended_desc_t *p = NULL;
//init tx chain
emac_config.dma_etx = (struct dma_extended_desc *)(&emac_dma_tx_chain_buf[0]);
emac_config.dma_etx = emac_dma_tx_chain_buf[0];
emac_config.cnt_tx = 0;
emac_config.cur_tx = 0;
emac_config.dirty_tx = 0;
dma_phy = (uint32_t)(emac_config.dma_etx);
p = emac_config.dma_etx;
for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++ ) {
dma_phy += sizeof(struct dma_extended_desc);
p = emac_dma_tx_chain_buf[0];
for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++) {
emac_clean_tx_desc(p);
p->basic.desc3 = dma_phy;
p->basic.desc2 = (uint32_t)(&emac_dma_tx_buf[0]) + (i * DMA_TX_BUF_SIZE);
p++;
/* point to the buffer */
p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
/* point to next descriptor */
p->basic.desc3 = (uint32_t)(emac_dma_tx_chain_buf[i + 1]);
p = emac_dma_tx_chain_buf[i + 1];
}
p->basic.desc3 = (uint32_t)(emac_config.dma_etx);
p->basic.desc2 = (uint32_t)(&emac_dma_tx_buf[0]) + (i * DMA_TX_BUF_SIZE);
//init desc0 desc1
emac_clean_tx_desc(p);
/* point to the buffer */
p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
/* point to first descriptor */
p->basic.desc3 = (uint32_t)(emac_config.dma_etx);
//init rx chain
emac_config.dma_erx = (struct dma_extended_desc *)(&emac_dma_rx_chain_buf[0]);
emac_config.dma_erx = emac_dma_rx_chain_buf[0];
emac_config.cnt_rx = 0;
emac_config.cur_rx = 0;
emac_config.dirty_rx = 0;
dma_phy = (uint32_t)(emac_config.dma_erx);
p = emac_config.dma_erx;
for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++ ) {
dma_phy += sizeof(struct dma_extended_desc);
emac_clean_rx_desc(p, (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE));
p->basic.desc3 = dma_phy;
p++;
p = emac_dma_rx_chain_buf[0];
for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++) {
emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
/* point to the buffer */
p->basic.desc3 = (uint32_t)(emac_dma_rx_chain_buf[i + 1]);
/* point to next descriptor */
p = emac_dma_rx_chain_buf[i + 1];
}
emac_clean_rx_desc(p, (uint32_t)(&emac_dma_rx_buf[0]) + (i * DMA_RX_BUF_SIZE));
/* point to the buffer */
emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
/* point to first descriptor */
p->basic.desc3 = (uint32_t)(emac_config.dma_erx);
}
@ -214,13 +229,14 @@ void esp_eth_smi_write(uint32_t reg_num, uint16_t value)
{
uint32_t phy_num = emac_config.phy_addr;
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1 ) {
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
REG_WRITE(EMAC_MIIDATA_REG, value);
REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | ((0x3) << 2));
REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) |
((phy_num & 0x1f) << 11) | ((0x3) << 2));
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1 ) {
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
}
@ -229,21 +245,24 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
uint32_t phy_num = emac_config.phy_addr;
uint16_t value = 0;
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1 ) {
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | (0x3 << 2));
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1 ) {
REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) |
((phy_num & 0x1f) << 11) | (0x3 << 2));
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
value = (REG_READ(EMAC_MIIDATA_REG) & 0xffff);
return value;
}
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms)
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value,
uint16_t value_mask, int timeout_ms)
{
unsigned start = xTaskGetTickCount();
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS;
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) /
portTICK_PERIOD_MS;
uint16_t current_value = 0;
while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) {
@ -253,13 +272,12 @@ esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t valu
}
vTaskDelay(1);
}
ESP_LOGE(TAG, "Timed out waiting for PHY register 0x%x to have value 0x%04x (mask 0x%04x). Current value 0x%04x",
ESP_LOGE(TAG, "Timed out waiting for PHY register 0x%x to have value 0x%04x(mask 0x%04x). Current value 0x%04x",
reg_num, value, value_mask, current_value);
return ESP_ERR_TIMEOUT;
}
static void emac_set_user_config_data(eth_config_t *config )
static void emac_set_user_config_data(eth_config_t *config)
{
emac_config.phy_addr = config->phy_addr;
emac_config.mac_mode = config->mac_mode;
@ -275,11 +293,12 @@ static void emac_set_user_config_data(eth_config_t *config )
emac_config.emac_flow_ctrl_enable = config->flow_ctrl_enable;
#else
if(config->flow_ctrl_enable == true) {
ESP_LOGE(TAG, "eth flow ctrl init err!!! Please run menuconfig and make sure DMA_RX_BUF_NUM > 9 .");
ESP_LOGE(TAG, "Can only configure flow_ctrl_enable==true if DMA_RX_BUF_NUM in menuconfig is >9. Disabling flow control.");
}
emac_config.emac_flow_ctrl_enable = false;
#endif
emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable;
emac_config.emac_phy_get_partner_pause_enable =
config->phy_get_partner_pause_enable;
emac_config.emac_phy_power_enable = config->phy_power_enable;
}
@ -347,12 +366,13 @@ static esp_err_t emac_verify_args(void)
ret = ESP_FAIL;
}
if (emac_config.emac_flow_ctrl_enable == true && emac_config.emac_phy_get_partner_pause_enable == NULL) {
if (emac_config.emac_flow_ctrl_enable == true &&
emac_config.emac_phy_get_partner_pause_enable == NULL) {
ESP_LOGE(TAG, "phy get partner pause enable func is null");
ret = ESP_FAIL;
}
if(emac_config.emac_phy_power_enable == NULL) {
if (emac_config.emac_phy_power_enable == NULL) {
ESP_LOGE(TAG, "phy power enable func is null");
ret = ESP_FAIL;
}
@ -368,12 +388,12 @@ static void emac_process_tx(void)
return;
}
xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY );
xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY);
while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) {
emac_clean_tx_desc(&(emac_config.dma_etx[emac_config.dirty_tx]));
while ((uint32_t)(emac_dma_tx_chain_buf[emac_config.dirty_tx]) != cur_tx_desc) {
emac_clean_tx_desc(emac_dma_tx_chain_buf[emac_config.dirty_tx]);
emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM;
emac_config.cnt_tx --;
emac_config.cnt_tx--;
if (emac_config.cnt_tx < 0) {
ESP_LOGE(TAG, "emac tx chain err");
@ -381,14 +401,14 @@ static void emac_process_tx(void)
cur_tx_desc = emac_read_tx_cur_reg();
}
xSemaphoreGiveRecursive( emac_tx_xMutex );
xSemaphoreGiveRecursive(emac_tx_xMutex);
}
void esp_eth_free_rx_buf(void *buf)
{
xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]), (uint32_t) buf);
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.cur_rx], (uint32_t)buf);
emac_config.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM;
emac_config.cnt_rx--;
if (emac_config.cnt_rx < 0) {
@ -396,11 +416,12 @@ void esp_eth_free_rx_buf(void *buf)
}
emac_poll_rx_cmd();
xSemaphoreGiveRecursive( emac_rx_xMutex );
xSemaphoreGiveRecursive(emac_rx_xMutex);
if (emac_config.emac_flow_ctrl_partner_support == true) {
portENTER_CRITICAL(&g_emac_mux);
if (pause_send == true && emac_config.cnt_rx < FLOW_CONTROL_LOW_WATERMARK) {
if (pause_send == true && emac_config.cnt_rx <
FLOW_CONTROL_LOW_WATERMARK) {
emac_send_pause_zero_frame_enable();
pause_send = false;
}
@ -412,7 +433,7 @@ static uint32_t IRAM_ATTR emac_get_rxbuf_count_in_intr(void)
{
uint32_t cnt = 0;
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
struct dma_extended_desc *cur_desc = (struct dma_extended_desc *)cur_rx_desc;
struct dma_extended_desc *cur_desc = (dma_extended_desc_t *)cur_rx_desc;
while (cur_desc->basic.desc0 == EMAC_DESC_RX_OWN && cnt < DMA_RX_BUF_NUM) {
cnt++;
@ -429,12 +450,16 @@ static void emac_process_rx(void)
}
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) {
while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc)) {
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
emac_config.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]),
(((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.dirty_rx],
(uint32_t)(emac_dma_rx_buf[emac_config.dirty_rx]));
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//if open this ,one intr can do many intrs ?
@ -453,16 +478,20 @@ static void emac_process_rx_unavail(void)
uint32_t dirty_cnt = 0;
while (dirty_cnt < DMA_RX_BUF_NUM) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break;
}
dirty_cnt ++;
dirty_cnt++;
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
emac_config.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]),
(((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.dirty_rx],
(uint32_t)(emac_dma_rx_buf[emac_config.dirty_rx]));
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
}
emac_enable_rx_intr();
@ -477,11 +506,11 @@ static void emac_process_rx_unavail(void)
return;
}
xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break;
}
@ -493,13 +522,15 @@ static void emac_process_rx_unavail(void)
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
}
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
}
emac_enable_rx_intr();
emac_enable_rx_unavail_intr();
xSemaphoreGiveRecursive( emac_rx_xMutex );
xSemaphoreGiveRecursive(emac_rx_xMutex);
}
static void emac_process_rx(void)
@ -510,31 +541,36 @@ static void emac_process_rx(void)
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
if (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) {
if (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx])) !=
cur_rx_desc) {
while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc) && emac_config.cnt_rx < DMA_RX_BUF_NUM ) {
while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc) &&
emac_config.cnt_rx < DMA_RX_BUF_NUM) {
emac_config.cnt_rx++;
if (emac_config.cnt_rx > DMA_RX_BUF_NUM ) {
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
ESP_LOGE(TAG, "emac rx buf err!!\n");
}
uint32_t tmp_dirty = emac_config.dirty_rx;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
cur_rx_desc = emac_read_rx_cur_reg();
}
} else {
if (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if ((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) == 0) {
if ((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 &
EMAC_DESC_RX_OWN) == 0) {
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break;
}
@ -543,18 +579,21 @@ static void emac_process_rx(void)
ESP_LOGE(TAG, "emac rx buf err!!!\n");
}
uint32_t tmp_dirty = emac_config.dirty_rx;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) %
DMA_RX_BUF_NUM;
//copy data to lwip
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
}
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
}
}
}
}
emac_enable_rx_intr();
xSemaphoreGiveRecursive( emac_rx_xMutex );
xSemaphoreGiveRecursive(emac_rx_xMutex);
}
#endif
@ -570,7 +609,8 @@ static void IRAM_ATTR emac_process_intr(void *arg)
if (event & EMAC_RECV_INT) {
emac_disable_rx_intr();
if (emac_config.emac_flow_ctrl_partner_support == true) {
if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && pause_send == false ) {
if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK &&
pause_send == false) {
pause_send = true;
emac_send_pause_frame_enable();
}
@ -591,7 +631,9 @@ static void IRAM_ATTR emac_process_intr(void *arg)
static void emac_set_macaddr_reg(void)
{
REG_SET_FIELD(EMAC_ADDR0HIGH_REG, EMAC_ADDRESS0_HI, (emac_config.macaddr[0] << 8) | (emac_config.macaddr[1]));
REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[2] << 24) | (emac_config.macaddr[3] << 16) | (emac_config.macaddr[4] << 8) | (emac_config.macaddr[5]));
REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[2] << 24) |
(emac_config.macaddr[3] << 16) | (emac_config.macaddr[4] << 8) |
(emac_config.macaddr[5]));
}
static void emac_check_phy_init(void)
@ -612,7 +654,8 @@ static void emac_check_phy_init(void)
emac_config.emac_flow_ctrl_partner_support = false;
#else
if (emac_config.emac_flow_ctrl_enable == true) {
if (emac_config.emac_phy_get_partner_pause_enable() == true && emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
if (emac_config.emac_phy_get_partner_pause_enable() == true &&
emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
emac_enable_flowctrl();
emac_config.emac_flow_ctrl_partner_support = true;
} else {
@ -635,7 +678,7 @@ static void emac_process_link_updown(bool link_status)
if (link_status == true) {
emac_check_phy_init();
ESP_LOGI(TAG, "eth link_up!!!");
ESP_LOGD(TAG, "eth link_up");
emac_enable_dma_tx();
emac_enable_dma_rx();
for (i = 0; i < PHY_LINK_CHECK_NUM; i++) {
@ -644,7 +687,7 @@ static void emac_process_link_updown(bool link_status)
evt.event_id = SYSTEM_EVENT_ETH_CONNECTED;
} else {
ESP_LOGI(TAG, "eth link_down!!!");
ESP_LOGD(TAG, "eth link_down");
emac_disable_dma_tx();
emac_disable_dma_rx();
evt.event_id = SYSTEM_EVENT_ETH_DISCONNECTED;
@ -667,31 +710,32 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
{
esp_err_t ret = ESP_OK;
if (emac_config.emac_status != EMAC_RUNTIME_START || emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
ESP_LOGI(TAG, "tx netif close");
if (emac_config.emac_status != EMAC_RUNTIME_START) {
ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d",
emac_config.emac_status);
ret = ERR_IF;
return ret;
}
xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY );
xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY);
if (emac_config.cnt_tx == DMA_TX_BUF_NUM - 1) {
ESP_LOGD(TAG, "tx buf full");
ret = ERR_MEM;
goto _exit;
}
memcpy((uint8_t *)(emac_config.dma_etx[emac_config.cur_tx].basic.desc2), (uint8_t *)buf, size);
memcpy(emac_dma_tx_buf[emac_config.cur_tx], buf, size);
emac_setup_tx_desc(&(emac_config.dma_etx[emac_config.cur_tx]), size);
emac_setup_tx_desc(emac_dma_tx_chain_buf[emac_config.cur_tx], size);
emac_config.cnt_tx ++;
emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM ;
emac_config.cnt_tx++;
emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM;
emac_poll_tx_cmd();
_exit:
xSemaphoreGiveRecursive( emac_tx_xMutex );
xSemaphoreGiveRecursive(emac_tx_xMutex);
return ret;
}
@ -702,17 +746,16 @@ static void emac_init_default_data(void)
void emac_process_link_check(void)
{
if (emac_config.emac_status != EMAC_RUNTIME_START ||
emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
if (emac_config.emac_status != EMAC_RUNTIME_START) {
return;
}
if (emac_config.emac_phy_check_link() == true ) {
if (emac_config.phy_link_up == false) {
if (emac_config.emac_phy_check_link()) {
if (!emac_config.phy_link_up) {
emac_process_link_updown(true);
}
} else {
if (emac_config.phy_link_up == true) {
if (emac_config.phy_link_up) {
emac_process_link_updown(false);
}
}
@ -725,8 +768,12 @@ void emac_link_check_func(void *pv_parameters)
static bool emac_link_check_timer_init(void)
{
emac_timer = xTimerCreate("emac_timer", (2000 / portTICK_PERIOD_MS),
pdTRUE, (void *)rand(), emac_link_check_func);
emac_timer = xTimerCreate("emac_timer",
(CONFIG_EMAC_CHECK_LINK_PERIOD_MS /
portTICK_PERIOD_MS),
pdTRUE,
NULL,
emac_link_check_func);
if (emac_timer == NULL) {
return false;
} else {
@ -761,10 +808,10 @@ static bool emac_link_check_timer_delete(void)
static void emac_start(void *param)
{
struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
struct emac_open_cmd *cmd = (struct emac_open_cmd *)(post_cmd->cmd);
ESP_LOGI(TAG , "emac start !!!\n");
ESP_LOGD(TAG, "emac start");
cmd->err = EMAC_CMD_OK;
emac_enable_clk(true);
@ -803,7 +850,7 @@ static void emac_start(void *param)
xSemaphoreGive(emac_g_sem);
}
ESP_LOGI(TAG, "emac start success !!!");
ESP_LOGD(TAG, "emac start success");
}
esp_err_t esp_eth_enable(void)
@ -849,8 +896,8 @@ cleanup:
static void emac_stop(void *param)
{
struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
ESP_LOGI(TAG, "emac stop");
struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param;
ESP_LOGD(TAG, "emac stop");
emac_link_check_timer_stop();
emac_link_check_timer_delete();
@ -871,7 +918,7 @@ static void emac_stop(void *param)
xSemaphoreGive(emac_g_sem);
}
ESP_LOGI(TAG, "emac stop success !!!");
ESP_LOGD(TAG, "emac stop success");
}
esp_err_t esp_eth_disable(void)
@ -906,7 +953,7 @@ esp_err_t esp_eth_disable(void)
static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par)
{
esp_err_t ret = ESP_OK;
struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)par;
struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)par;
xTaskHandle task_hdl = xTaskGetCurrentTaskHandle();
if (emac_task_hdl != task_hdl) {
@ -948,7 +995,7 @@ void emac_task(void *pv)
emac_event_t e;
for (;;) {
if (xQueueReceive(emac_xqueue, &e, (portTickType)portMAX_DELAY) == pdTRUE) {
if (xQueueReceive(emac_xqueue, &e, portMAX_DELAY) == pdTRUE) {
portENTER_CRITICAL(&g_emac_mux);
emac_sig_cnt[e.sig]--;
portEXIT_CRITICAL(&g_emac_mux);
@ -1020,8 +1067,18 @@ esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par)
esp_err_t esp_eth_init(eth_config_t *config)
{
esp_event_set_default_eth_handlers();
return esp_eth_init_internal(config);
/* dynamically alloc memory for ethernet dma */
for (int i = 0; i < DMA_RX_BUF_NUM; i++) {
emac_dma_rx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), MALLOC_CAP_DMA);
emac_dma_rx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_RX_BUF_SIZE, MALLOC_CAP_DMA);
}
for (int i = 0; i < DMA_TX_BUF_NUM; i++) {
emac_dma_tx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), MALLOC_CAP_DMA);
emac_dma_tx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_TX_BUF_SIZE, MALLOC_CAP_DMA);
}
esp_event_set_default_eth_handlers();
return esp_eth_init_internal(config);
}
esp_err_t esp_eth_init_internal(eth_config_t *config)
@ -1033,7 +1090,7 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
emac_init_default_data();
if (config != NULL ) {
if (config != NULL) {
emac_set_user_config_data(config);
}
@ -1051,31 +1108,28 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
if (emac_config.clock_mode != ETH_CLOCK_GPIO0_IN) {
// 50 MHz = 40MHz * (6 + 4) / (2 * (2 + 2) = 400MHz / 8
rtc_clk_apll_enable(1, 0, 0, 6, 2);
// the next to values have to be set AFTER "periph_module_enable" is called
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_H_DIV_NUM, 0);
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_DIV_NUM, 0);
if (emac_config.clock_mode == ETH_CLOCK_GPIO0_OUT) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
REG_WRITE(PIN_CTRL, 6);
ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO0");
} else if (emac_config.clock_mode == ETH_CLOCK_GPIO16_OUT) {
if (emac_config.clock_mode == ETH_CLOCK_GPIO16_OUT) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO16");
} else if (emac_config.clock_mode == ETH_CLOCK_GPIO17_OUT) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U,
FUNC_GPIO17_EMAC_CLK_OUT_180);
ESP_LOGD(TAG, "EMAC 50MHz inverted clock output on GPIO17");
}
}
emac_enable_clk(true);
REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII);
REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL,
EMAC_EX_PHY_INTF_RMII);
emac_dma_init();
if (emac_config.clock_mode == ETH_CLOCK_GPIO0_IN) {
// external clock on GPIO0
REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
REG_SET_BIT(EMAC_EX_OSCCLK_CONF_REG, EMAC_EX_OSC_CLK_SEL);
ESP_LOGD(TAG, "External clock input 50MHz on GPIO0");
if (emac_config.mac_mode == ETH_MODE_MII) {
@ -1084,8 +1138,8 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
}
} else {
// internal clock by APLL
REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
REG_CLR_BIT(EMAC_EX_OSCCLK_CONF_REG, EMAC_EX_OSC_CLK_SEL);
}
@ -1101,7 +1155,8 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
emac_rx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_tx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t));
xTaskCreate(emac_task, "emacT", 2048, NULL, EMAC_TASK_PRIORITY, &emac_task_hdl);
xTaskCreate(emac_task, "emacT", 2048, NULL, EMAC_TASK_PRIORITY,
&emac_task_hdl);
emac_enable_clk(false);
esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL);
@ -1111,3 +1166,43 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
_exit:
return ret;
}
esp_err_t esp_eth_deinit(void)
{
esp_err_t ret = ESP_FAIL;
if (!emac_task_hdl) {
ret = ESP_ERR_INVALID_STATE;
goto _exit;
}
vTaskDelete(emac_task_hdl);
emac_task_hdl = NULL;
vQueueDelete(emac_xqueue);
vSemaphoreDelete(emac_tx_xMutex);
vSemaphoreDelete(emac_rx_xMutex);
vSemaphoreDelete(emac_g_sem);
emac_reset_dma_chain();
emac_config.emac_phy_power_enable(false);
periph_module_disable(PERIPH_EMAC_MODULE);
emac_config.emac_status = EMAC_RUNTIME_NOT_INIT;
/* free memory that dynamically allocted */
for (int i = 0; i < DMA_RX_BUF_NUM; i++) {
free(emac_dma_rx_chain_buf[i]);
free(emac_dma_rx_buf[i]);
emac_dma_rx_chain_buf[i] = NULL;
emac_dma_rx_buf[i] = NULL;
}
for (int i = 0; i < DMA_TX_BUF_NUM; i++) {
free(emac_dma_tx_chain_buf[i]);
free(emac_dma_tx_buf[i]);
emac_dma_tx_chain_buf[i] = NULL;
emac_dma_tx_buf[i] = NULL;
}
ret = ESP_OK;
_exit:
return ret;
}

View File

@ -29,10 +29,9 @@ typedef enum {
} eth_mode_t;
typedef enum {
ETH_CLOCK_GPIO0_IN = 0,
ETH_CLOCK_GPIO0_OUT = 1,
ETH_CLOCK_GPIO0_IN = 0,
ETH_CLOCK_GPIO16_OUT = 2,
ETH_CLOCK_GPIO17_OUT = 3
ETH_CLOCK_GPIO17_OUT = 3,
} eth_clock_mode_t;
typedef enum {
@ -125,6 +124,16 @@ typedef struct {
*/
esp_err_t esp_eth_init(eth_config_t *config);
/**
* @brief Deinit ethernet mac
*
* @return
* - ESP_OK
* - ESP_FAIL
* - ESP_ERR_INVALID_STATE
*/
esp_err_t esp_eth_deinit(void);
/**
* @brief Init Ethernet mac driver only
*
@ -236,7 +245,8 @@ esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t valu
*
* @return ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out.
*/
static inline esp_err_t esp_eth_smi_wait_set(uint32_t reg_num, uint16_t value_mask, int timeout_ms) {
static inline esp_err_t esp_eth_smi_wait_set(uint32_t reg_num, uint16_t value_mask, int timeout_ms)
{
return esp_eth_smi_wait_value(reg_num, value_mask, value_mask, timeout_ms);
}
@ -265,7 +275,7 @@ void esp_eth_get_mac(uint8_t mac[6]);
*
* @param[in] mac: the Mac address.
*
* @return
* @return
* - ESP_OK: succeed
* - ESP_ERR_INVALID_MAC: invalid mac address
*/

View File

@ -0,0 +1,5 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View File

@ -0,0 +1,87 @@
/**
* @brief This test has just run in the ESP32_Ethernet_V3 board, which featured
* in PoE submodule and TLK110 PHY. The 50MHz clock used by MAC and PHY is
* supplied by external oscillator through GPIO0.
*
* @file test_emac_deinit.c
* @author morris
* @date 2018-08-24
*/
#include <string.h>
#include "unity.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_event_loop.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "rom/gpio.h"
#include "tcpip_adapter.h"
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#include "esp_wifi.h"
#include "eth_phy/phy_tlk110.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
static const char *TAG = "eth_test_deinit";
#define PIN_PHY_POWER 17
#define PIN_SMI_MDC 23
#define PIN_SMI_MDIO 18
#define CONFIG_PHY_ADDRESS 31
#define CONFIG_PHY_CLOCK_MODE 0
static void phy_device_power_enable_via_gpio(bool enable)
{
if (!enable) {
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
}
gpio_pad_select_gpio(PIN_PHY_POWER);
gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT);
if (enable == true) {
gpio_set_level(PIN_PHY_POWER, 1);
ESP_LOGI(TAG, "power on ethernet phy");
} else {
gpio_set_level(PIN_PHY_POWER, 0);
ESP_LOGI(TAG, "power off ethernet phy");
}
vTaskDelay(1); // Allow the power up/down to take effect, min 300us
if (enable) {
/* operates the default phy-specific power on function */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
}
}
static void eth_gpio_config_rmii(void)
{
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
}
TEST_CASE("test emac deinit", "[ethernet][ignore]")
{
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
config.phy_addr = CONFIG_PHY_ADDRESS;
config.gpio_config = eth_gpio_config_rmii;
config.tcpip_input = tcpip_adapter_eth_input;
config.clock_mode = CONFIG_PHY_CLOCK_MODE;
config.phy_power_enable = phy_device_power_enable_via_gpio;
ESP_ERROR_CHECK(esp_eth_init(&config));
ESP_ERROR_CHECK(esp_eth_enable());
vTaskDelay(2000 / portTICK_RATE_MS);
ESP_ERROR_CHECK(esp_eth_disable());
ESP_ERROR_CHECK(esp_eth_deinit());
}

View File

@ -258,8 +258,11 @@ static inline unsigned portENTER_CRITICAL_NESTED() {
//Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force
//the stack memory to always be internal.
#define pvPortMallocTcbMem(size) heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define pvPortMallocStackMem(size) heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define pvPortMallocTcbMem(size) heap_caps_malloc(size, portTcbMemoryCaps)
#define pvPortMallocStackMem(size) heap_caps_malloc(size, portStackMemoryCaps)
//xTaskCreateStatic uses these functions to check incoming memory.
#define portVALID_TCB_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))

View File

@ -23,7 +23,8 @@
#define NO_OF_TSKS 3
#define DELAY_TICKS 2
#define HEAP_CAPS (MALLOC_CAP_INTERNAL|MALLOC_CAP_DEFAULT)
/* Caps of all memory which is allocated from when a task is created */
#define HEAP_CAPS (portTcbMemoryCaps | portStackMemoryCaps)
#define DELAY_US_ITERATIONS 1000

View File

@ -88,23 +88,42 @@ TEST_CASE("Check if reserved DMA pool still can allocate even when malloc()'ed m
#endif
/* As you see, we are desperately trying to outsmart the compiler, so that it
* doesn't warn about oversized allocations in the next two unit tests.
* To be removed when we switch to GCC 8.2 and add
* -Wno-alloc-size-larger-than=PTRDIFF_MAX to CFLAGS for this file.
*/
void* (*g_test_malloc_ptr)(size_t) = &malloc;
void* (*g_test_calloc_ptr)(size_t, size_t) = &calloc;
void* test_malloc_wrapper(size_t size)
{
return (*g_test_malloc_ptr)(size);
}
void* test_calloc_wrapper(size_t count, size_t size)
{
return (*g_test_calloc_ptr)(count, size);
}
TEST_CASE("alloc overflows should all fail", "[heap]")
{
/* allocates 8 bytes */
TEST_ASSERT_NULL(calloc(SIZE_MAX / 2 + 4, 2));
TEST_ASSERT_NULL(test_calloc_wrapper(SIZE_MAX / 2 + 4, 2));
/* will overflow if any poisoning is enabled
(should fail for sensible OOM reasons, otherwise) */
TEST_ASSERT_NULL(malloc(SIZE_MAX - 1));
TEST_ASSERT_NULL(calloc(SIZE_MAX - 1, 1));
TEST_ASSERT_NULL(test_malloc_wrapper(SIZE_MAX - 1));
TEST_ASSERT_NULL(test_calloc_wrapper(SIZE_MAX - 1, 1));
}
TEST_CASE("unreasonable allocs should all fail", "[heap]")
{
TEST_ASSERT_NULL(calloc(16, 1024*1024));
TEST_ASSERT_NULL(malloc(16*1024*1024));
TEST_ASSERT_NULL(malloc(SIZE_MAX / 2));
TEST_ASSERT_NULL(malloc(SIZE_MAX - 256));
TEST_ASSERT_NULL(malloc(xPortGetFreeHeapSize() - 1));
TEST_ASSERT_NULL(test_calloc_wrapper(16, 1024*1024));
TEST_ASSERT_NULL(test_malloc_wrapper(16*1024*1024));
TEST_ASSERT_NULL(test_malloc_wrapper(SIZE_MAX / 2));
TEST_ASSERT_NULL(test_malloc_wrapper(SIZE_MAX - 256));
TEST_ASSERT_NULL(test_malloc_wrapper(xPortGetFreeHeapSize() - 1));
}

View File

@ -2577,7 +2577,7 @@ test cases:
- ID: BTSTK_GAP_14007
<<: *GAP_CASE
test point 2: BLE set random address test
summary: BLE set random address as resolvable private address
summary: BLE set random address as resolvable private address and cannot be scan
initial condition: BLE_INIT_SMP
steps: |
1. SSC1 set adv params and config local privacy as true
@ -2604,7 +2604,7 @@ test cases:
- ID: BTSTK_GAP_14008
<<: *GAP_CASE
test point 2: BLE set random address test
summary: BLE set random address as resolvable private address
summary: disconnect after encryption and set random address as resolvable private address and reconnect
steps: |
1. SSC2 set AuthReqMode and IOCAP,set RspKey as Enc and IRK
2. pairing
@ -2651,7 +2651,7 @@ test cases:
- ID: BTSTK_GAP_14009
<<: *GAP_CASE
test point 2: BLE set random address test
summary: BLE set random address as resolvable private address
summary: reboot after BLE DUT encryption and set random address as resolvable private address
steps: |
1. SSC2 set AuthReqMode and IOCAP,set RspKey as Enc and IRK
2. pairing

View File

@ -1547,7 +1547,7 @@ test cases:
cmd set:
- ""
- *primary_service_discovery
- - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v -x01 -w 1"
- - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01 -w 1"
- ["P SSC1 C +GATTC:WriteOnce"]
- ID: BTSTK_GATT_25008
<<: *GATT_CASE
@ -1685,9 +1685,9 @@ test cases:
cmd set:
- ""
- *primary_service_discovery
- - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v -x01 -w 1"
- - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v 0x01 -w 1"
- ["R SSC1 C +GATTC:Write,OK"]
- - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v -x01 -w 1"
- - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v 0x01 -w 1"
- ["R SSC1 C +GATTC:Write,OK"]
- ID: BTSTK_GATT_25015
<<: *GATT_CASE

View File

@ -128,7 +128,7 @@ test cases:
test point 1: basic function
test point 2: mesh network establish
version: v1 (2017-7-20)
- CI ready: 'Yes'
- CI ready: 'No'
ID: MESH_EST_0404
SDK: ESP32_IDF
Test App: SSC_MESH
@ -177,7 +177,7 @@ test cases:
test point 1: basic function
test point 2: mesh network re-establish
version: v1 (2017-7-20)
- CI ready: 'Yes'
- CI ready: 'No'
ID: MESH_EST_0405
SDK: ESP32_IDF
Test App: SSC_MESH

View File

@ -1712,7 +1712,7 @@ decode_next:
offset_max -= q->len;
if ((offset < offset_max) && offset_max) {
q = q->next;
LWIP_ASSERT("next pbuf was null", q);
LWIP_ERROR("offset pointed to next pbuf which is null", q , return ERR_VAL;);
options = (u8_t*)q->payload;
} else {
/* We've run out of bytes, probably no end marker. Don't proceed. */

View File

@ -1,7 +1,7 @@
COMPONENTS_DIR=../..
CFLAGS=-std=gnu99 -Og -ggdb -ffunction-sections -fdata-sections -nostdlib -Wall -Werror=all -Wno-int-to-pointer-cast -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wextra \
-Wno-unused-parameter -Wno-sign-compare -Wno-address -Wno-unused-variable -DESP_PLATFORM -D IDF_VER=\"v3.1\" -MMD -MP -DWITH_POSIX
INC_DIRS=-I . -I $(COMPONENTS_DIR)/lwip/include/lwip -I $(COMPONENTS_DIR)/lwip/include/lwip/port -I $(COMPONENTS_DIR)/lwip/include/lwip/posix -I $(COMPONENTS_DIR)/lwip/apps/ping -I $(COMPONENTS_DIR)/app_trace/include -I $(COMPONENTS_DIR)/app_update/include -I $(COMPONENTS_DIR)/bootloader_support/include -I $(COMPONENTS_DIR)/bt/include -I $(COMPONENTS_DIR)/coap/port/include -I $(COMPONENTS_DIR)/coap/port/include/coap -I $(COMPONENTS_DIR)/coap/libcoap/include -I \ $(COMPONENTS_DIR)/coap/libcoap/include/coap -I $(COMPONENTS_DIR)/console -I $(COMPONENTS_DIR)/cxx/include -I $(COMPONENTS_DIR)/driver/include -I $(COMPONENTS_DIR)/esp-tls -I $(COMPONENTS_DIR)/esp32/include -I $(COMPONENTS_DIR)/esp_adc_cal/include -I $(COMPONENTS_DIR)/ethernet/include -I $(COMPONENTS_DIR)/expat/port/include -I $(COMPONENTS_DIR)/expat/include/expat -I $(COMPONENTS_DIR)/fatfs/src -I $(COMPONENTS_DIR)/freertos/include -I $(COMPONENTS_DIR)/heap/include -I \ $(COMPONENTS_DIR)/idf_test/include -I $(COMPONENTS_DIR)/jsmn/include -I $(COMPONENTS_DIR)/json/cJSON -I $(COMPONENTS_DIR)/libsodium/libsodium/src/libsodium/include -I $(COMPONENTS_DIR)/libsodium/port_include -I $(COMPONENTS_DIR)/log/include -I /home/david/esp/esp-idf/examples/wifi/simple_wifi/main/include -I $(COMPONENTS_DIR)/mbedtls/port/include -I $(COMPONENTS_DIR)/mbedtls/include -I $(COMPONENTS_DIR)/mdns/include -I $(COMPONENTS_DIR)/micro-ecc/micro-ecc -I \ $(COMPONENTS_DIR)/newlib/platform_include -I $(COMPONENTS_DIR)/newlib/include -I $(COMPONENTS_DIR)/nghttp/port/include -I $(COMPONENTS_DIR)/nghttp/nghttp2/lib/includes -I $(COMPONENTS_DIR)/nvs_flash/include -I $(COMPONENTS_DIR)/openssl/include -I $(COMPONENTS_DIR)/pthread/include -I $(COMPONENTS_DIR)/sdmmc/include -I $(COMPONENTS_DIR)/smartconfig/include -I $(COMPONENTS_DIR)/soc/esp32/include -I $(COMPONENTS_DIR)/soc/include -I $(COMPONENTS_DIR)/spi_flash/include -I \ $(COMPONENTS_DIR)/spiffs/include -I $(COMPONENTS_DIR)/tcpip_adapter/include -I $(COMPONENTS_DIR)/ulp/include -I $(COMPONENTS_DIR)/vfs/include -I $(COMPONENTS_DIR)/wear_levelling/include -I $(COMPONENTS_DIR)/wpa_supplicant/include -I $(COMPONENTS_DIR)/wpa_supplicant/port/include -I $(COMPONENTS_DIR)/esp32/include -I $(COMPONENTS_DIR)/xtensa-debug-module/include
INC_DIRS=-I . -I $(COMPONENTS_DIR)/newlib/platform_include -I $(COMPONENTS_DIR)/newlib/include -I $(COMPONENTS_DIR)/driver/include -I $(COMPONENTS_DIR)/esp32/include -I $(COMPONENTS_DIR)/ethernet/include -I $(COMPONENTS_DIR)/freertos/include -I $(COMPONENTS_DIR)/heap/include -I $(COMPONENTS_DIR)/lwip/include/lwip -I $(COMPONENTS_DIR)/lwip/include/lwip/port -I $(COMPONENTS_DIR)/lwip/include/lwip/posix -I $(COMPONENTS_DIR)/lwip/apps/ping -I $(COMPONENTS_DIR)/soc/esp32/include -I $(COMPONENTS_DIR)/soc/include -I $(COMPONENTS_DIR)/tcpip_adapter/include -I $(COMPONENTS_DIR)/xtensa-debug-module/include
TEST_NAME=test
FUZZ=afl-fuzz
LD=$(CC)
@ -55,4 +55,4 @@ $(TEST_NAME): $(OBJECTS)
@$(LD) $(OBJECTS) -o $@ $(LDLIBS)
fuzz: $(TEST_NAME)
@$(FUZZ) -t 500 -i "$(SAMPLE_PACKETS)" -o "out" -- ./$(TEST_NAME)
@$(FUZZ) -t 5000+ -i "$(SAMPLE_PACKETS)" -o "out" -- ./$(TEST_NAME)

View File

@ -9,6 +9,9 @@ const ip_addr_t ip_addr_any;
ip4_addr_t server_ip;
struct netif mynetif;
// dhcps callback
void dhcp_test_dhcps_cb (u8_t client_ip[4]) {}
// Dependency injected static function to pass the packet into parser
void dhcp_test_handle_dhcp(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
void dhcp_test_init_di();
@ -26,6 +29,7 @@ int main(int argc, char** argv)
dhcp_test_init_di();
IP4_ADDR(&server_ip, 192,168,4,1);
dhcps_set_new_lease_cb(dhcp_test_dhcps_cb);
dhcps_start(&mynetif, server_ip);
#ifdef INSTR_IS_OFF

View File

@ -26,6 +26,7 @@
#include <limits.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/param.h>
#include "mbedtls/bignum.h"
#include "rom/bigint.h"
#include "soc/hwcrypto_reg.h"
@ -41,6 +42,20 @@
#include "freertos/task.h"
#include "freertos/semphr.h"
/* Some implementation notes:
*
* - Naming convention x_words, y_words, z_words for number of words (limbs) used in a particular
* bignum. This number may be less than the size of the bignum
*
* - Naming convention hw_words for the hardware length of the operation. This number is always
* rounded up to a 512 bit multiple, and may be larger than any of the numbers involved in the
* calculation.
*
* - Timing behaviour of these functions will depend on the length of the inputs. This is fundamentally
* the same constraint as the software mbedTLS implementations, and relies on the same
* countermeasures (exponent blinding, etc) which are used in mbedTLS.
*/
static const __attribute__((unused)) char *TAG = "bignum";
#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */
@ -103,49 +118,49 @@ void esp_mpi_release_hardware( void )
_lock_release(&mpi_lock);
}
/* Number of words used to hold 'mpi', rounded up to nearest
16 words (512 bits) to match hardware support.
/* Convert bit count to word count
*/
static inline size_t bits_to_words(size_t bits)
{
return (bits + 31) / 32;
}
/* Round up number of words to nearest
512 bit (16 word) block count.
*/
static inline size_t hardware_words(size_t words)
{
return (words + 0xF) & ~0xF;
}
/* Number of words used to hold 'mpi'.
Equivalent of bits_to_words(mbedtls_mpi_bitlen(mpi)), but uses less cycles if the
exact bit count is not needed.
Note that mpi->n (size of memory buffer) may be higher than this
number, if the high bits are mostly zeroes.
This implementation may cause the caller to leak a small amount of
timing information when an operation is performed (length of a
given mpi value, rounded to nearest 512 bits), but not all mbedTLS
RSA operations succeed if we use mpi->N as-is (buffers are too long).
*/
static inline size_t hardware_words_needed(const mbedtls_mpi *mpi)
static inline size_t word_length(const mbedtls_mpi *mpi)
{
size_t res = 1;
for(size_t i = 0; i < mpi->n; i++) {
if( mpi->p[i] != 0 ) {
res = i + 1;
for(size_t i = mpi->n; i > 0; i--) {
if( mpi->p[i - 1] != 0 ) {
return i;
}
}
res = (res + 0xF) & ~0xF;
return res;
}
/* Convert number of bits to number of words, rounded up to nearest
512 bit (16 word) block count.
*/
static inline size_t bits_to_hardware_words(size_t num_bits)
{
return ((num_bits + 511) / 512) * 16;
return 0;
}
/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'.
If num_words is higher than the number of words in the bignum then
If hw_words is higher than the number of words in the bignum then
these additional words will be zeroed in the memory buffer.
As this function only writes to DPORT memory, no DPORT_STALL_OTHER_CPU_START()
is required.
*/
static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words)
static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t hw_words)
{
uint32_t *pbase = (uint32_t *)mem_base;
uint32_t copy_words = num_words < mpi->n ? num_words : mpi->n;
uint32_t copy_words = hw_words < mpi->n ? hw_words : mpi->n;
/* Copy MPI data to memory block registers */
for (int i = 0; i < copy_words; i++) {
@ -153,7 +168,7 @@ static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, s
}
/* Zero any remaining memory block data */
for (int i = copy_words; i < num_words; i++) {
for (int i = copy_words; i < hw_words; i++) {
pbase[i] = 0;
}
@ -164,27 +179,21 @@ static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, s
Reads num_words words from block.
Can return a failure result if fails to grow the MPI result.
Cannot be called inside DPORT_STALL_OTHER_CPU_START() (as may allocate memory).
Bignum 'x' should already be grown to at least num_words by caller (can be done while
calculation is in progress, to save some cycles)
*/
static inline int mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words)
static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words)
{
int ret = 0;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow(x, num_words) );
assert(x->n >= num_words);
/* Copy data from memory block registers */
esp_dport_access_read_buffer(x->p, mem_base, num_words);
/* Zero any remaining limbs in the bignum, if the buffer is bigger
than num_words */
for(size_t i = num_words; i < x->n; i++) {
x->p[i] = 0;
}
asm volatile ("memw");
cleanup:
return ret;
}
@ -245,9 +254,6 @@ static int calculate_rinv(mbedtls_mpi *Rinv, const mbedtls_mpi *M, int num_words
/* Begin an RSA operation. op_reg specifies which 'START' register
to write to.
Because the only DPORT operations here are writes,
does not need protecting via DPORT_STALL_OTHER_CPU_START();
*/
static inline void start_op(uint32_t op_reg)
{
@ -261,9 +267,6 @@ static inline void start_op(uint32_t op_reg)
}
/* Wait for an RSA operation to complete.
This should NOT be called inside a DPORT_STALL_OTHER_CPU_START(), as it will stall the other CPU for an unacceptably long
period (and - depending on config - may require interrupts enabled).
*/
static inline void wait_op_complete(uint32_t op_reg)
{
@ -284,7 +287,7 @@ static inline void wait_op_complete(uint32_t op_reg)
}
/* Sub-stages of modulo multiplication/exponentiation operations */
inline static int modular_multiply_finish(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words);
inline static int modular_multiply_finish(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t hw_words, size_t z_words);
/* Z = (X * Y) mod M
@ -293,27 +296,33 @@ inline static int modular_multiply_finish(mbedtls_mpi *Z, const mbedtls_mpi *X,
int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M)
{
int ret;
size_t num_words = hardware_words_needed(M);
size_t x_bits = mbedtls_mpi_bitlen(X);
size_t y_bits = mbedtls_mpi_bitlen(Y);
size_t m_bits = mbedtls_mpi_bitlen(M);
size_t z_bits = MIN(m_bits, x_bits + y_bits);
size_t x_words = bits_to_words(x_bits);
size_t y_words = bits_to_words(y_bits);
size_t m_words = bits_to_words(m_bits);
size_t z_words = bits_to_words(z_bits);
size_t hw_words = hardware_words(MAX(x_words, MAX(y_words, m_words))); /* longest operand */
mbedtls_mpi Rinv;
mbedtls_mpi_uint Mprime;
/* Calculate and load the first stage montgomery multiplication */
mbedtls_mpi_init(&Rinv);
MBEDTLS_MPI_CHK(calculate_rinv(&Rinv, M, num_words));
MBEDTLS_MPI_CHK(calculate_rinv(&Rinv, M, hw_words));
Mprime = modular_inverse(M);
esp_mpi_acquire_hardware();
/* (As the following are all writes to DPORT memory, no DPORT_STALL_OTHER_CPU_START is required.) */
/* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */
mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, num_words);
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words);
mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, &Rinv, num_words);
mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, hw_words);
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words);
mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, &Rinv, hw_words);
DPORT_REG_WRITE(RSA_M_DASH_REG, (uint32_t)Mprime);
/* "mode" register loaded with number of 512-bit blocks, minus 1 */
DPORT_REG_WRITE(RSA_MULT_MODE_REG, (num_words / 16) - 1);
DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hw_words / 16) - 1);
/* Execute first stage montgomery multiplication */
start_op(RSA_MULT_START_REG);
@ -321,7 +330,7 @@ int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
wait_op_complete(RSA_MULT_START_REG);
/* execute second stage */
ret = modular_multiply_finish(Z, X, Y, num_words);
ret = modular_multiply_finish(Z, X, Y, hw_words, z_words);
esp_mpi_release_hardware();
@ -343,31 +352,20 @@ int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi* Y, const mbedtls_mpi* M, mbedtls_mpi* _Rinv )
{
int ret = 0;
size_t z_words = hardware_words_needed(Z);
size_t x_words = hardware_words_needed(X);
size_t y_words = hardware_words_needed(Y);
size_t m_words = hardware_words_needed(M);
size_t num_words;
size_t x_words = word_length(X);
size_t y_words = word_length(Y);
size_t m_words = word_length(M);
/* "all numbers must be the same length", so choose longest number
as cardinal length of operation...
*/
size_t hw_words = hardware_words(MAX(m_words, MAX(x_words, y_words)));
mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */
mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */
mbedtls_mpi_uint Mprime;
/* "all numbers must be the same length", so choose longest number
as cardinal length of operation...
*/
num_words = z_words;
if (x_words > num_words) {
num_words = x_words;
}
if (y_words > num_words) {
num_words = y_words;
}
if (m_words > num_words) {
num_words = m_words;
}
if (num_words * 32 > 4096) {
if (hw_words * 32 > 4096) {
return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
}
@ -380,30 +378,31 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi
Rinv = _Rinv;
}
if (Rinv->p == NULL) {
MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words));
MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, hw_words));
}
Mprime = modular_inverse(M);
esp_mpi_acquire_hardware();
/* (As the following are all writes to DPORT memory, no DPORT_STALL_OTHER_CPU_START is required.) */
/* "mode" register loaded with number of 512-bit blocks, minus 1 */
DPORT_REG_WRITE(RSA_MODEXP_MODE_REG, (num_words / 16) - 1);
DPORT_REG_WRITE(RSA_MODEXP_MODE_REG, (hw_words / 16) - 1);
/* Load M, X, Rinv, M-prime (M-prime is mod 2^32) */
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words);
mpi_to_mem_block(RSA_MEM_Y_BLOCK_BASE, Y, num_words);
mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, num_words);
mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Rinv, num_words);
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words);
mpi_to_mem_block(RSA_MEM_Y_BLOCK_BASE, Y, hw_words);
mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, hw_words);
mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Rinv, hw_words);
DPORT_REG_WRITE(RSA_M_DASH_REG, Mprime);
start_op(RSA_START_MODEXP_REG);
/* X ^ Y may actually be shorter than M, but unlikely when used for crypto */
MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, m_words) );
wait_op_complete(RSA_START_MODEXP_REG);
ret = mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, num_words);
mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, m_words);
esp_mpi_release_hardware();
cleanup:
@ -417,55 +416,56 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi
#endif /* MBEDTLS_MPI_EXP_MOD_ALT */
/* Second & final step of a modular multiply - load second multiplication
* factor Y, run the multiply, read back the result into Z.
* factor Y, run the operation (modular inverse), read back the result
* into Z.
*
* Called from both mbedtls_mpi_exp_mod and mbedtls_mpi_mod_mpi.
*
* @param Z result value
* @param X first multiplication factor (used to set sign of result).
* @param Y second multiplication factor.
* @param num_words size of modulo operation, in words (limbs).
* Should already be rounded up to a multiple of 16 words (512 bits) & range checked.
* @param hw_words Size of the hardware operation, in words
* @param z_words Size of the expected result, in words (may be less than hw_words).
* Z will be grown to at least this length.
*
* Caller must have already called esp_mpi_acquire_hardware().
*/
static int modular_multiply_finish(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words)
static int modular_multiply_finish(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t hw_words, size_t z_words)
{
int ret = 0;
/* Load Y to X input memory block, rerun */
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, num_words);
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, hw_words);
start_op(RSA_MULT_START_REG);
MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, z_words) );
wait_op_complete(RSA_MULT_START_REG);
/* Read result into Z */
ret = mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, num_words);
mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, z_words);
Z->s = X->s * Y->s;
cleanup:
return ret;
}
#if defined(MBEDTLS_MPI_MUL_MPI_ALT) /* MBEDTLS_MPI_MUL_MPI_ALT */
static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words);
static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t Y_bits, size_t words_result);
static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t z_words);
static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t Y_bits, size_t z_words);
/* Z = X * Y */
int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y )
{
int ret = 0;
size_t bits_x, bits_y, words_x, words_y, words_mult, words_z;
/* Count words needed for X & Y in hardware */
bits_x = mbedtls_mpi_bitlen(X);
bits_y = mbedtls_mpi_bitlen(Y);
/* Convert bit counts to words, rounded up to 512-bit
(16 word) blocks */
words_x = bits_to_hardware_words(bits_x);
words_y = bits_to_hardware_words(bits_y);
size_t x_bits = mbedtls_mpi_bitlen(X);
size_t y_bits = mbedtls_mpi_bitlen(Y);
size_t x_words = bits_to_words(x_bits);
size_t y_words = bits_to_words(y_bits);
size_t z_words = bits_to_words(x_bits + y_bits);
size_t hw_words = hardware_words(MAX(x_words, y_words)); // length of one operand in hardware
/* Short-circuit eval if either argument is 0 or 1.
@ -473,31 +473,22 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
argument will sometimes call in here when one
argument is too large for the hardware unit, but the other
argument is zero or one.
This leaks some timing information, although overall there is a
lot less timing variation than a software MPI approach.
*/
if (bits_x == 0 || bits_y == 0) {
if (x_bits == 0 || y_bits == 0) {
mbedtls_mpi_lset(Z, 0);
return 0;
}
if (bits_x == 1) {
if (x_bits == 1) {
ret = mbedtls_mpi_copy(Z, Y);
Z->s *= X->s;
return ret;
}
if (bits_y == 1) {
if (y_bits == 1) {
ret = mbedtls_mpi_copy(Z, X);
Z->s *= Y->s;
return ret;
}
words_mult = (words_x > words_y ? words_x : words_y);
/* Result Z has to have room for double the larger factor */
words_z = words_mult * 2;
/* If either factor is over 2048 bits, we can't use the standard hardware multiplier
(it assumes result is double longest factor, and result is max 4096 bits.)
@ -505,21 +496,19 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
multiplication doesn't have the same restriction, so result is simply the
number of bits in X plus number of bits in in Y.)
*/
if (words_mult * 32 > 2048) {
/* Calculate new length of Z */
words_z = bits_to_hardware_words(bits_x + bits_y);
if (words_z * 32 <= 4096) {
if (hw_words * 32 > 2048) {
if (z_words * 32 <= 4096) {
/* Note: it's possible to use mpi_mult_mpi_overlong
for this case as well, but it's very slightly
slower and requires a memory allocation.
*/
return mpi_mult_mpi_failover_mod_mult(Z, X, Y, words_z);
return mpi_mult_mpi_failover_mod_mult(Z, X, Y, z_words);
} else {
/* Still too long for the hardware unit... */
if(bits_y > bits_x) {
return mpi_mult_mpi_overlong(Z, X, Y, bits_y, words_z);
if(y_words > x_words) {
return mpi_mult_mpi_overlong(Z, X, Y, y_words, z_words);
} else {
return mpi_mult_mpi_overlong(Z, Y, X, bits_x, words_z);
return mpi_mult_mpi_overlong(Z, Y, X, x_words, z_words);
}
}
}
@ -529,8 +518,8 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
esp_mpi_acquire_hardware();
/* Copy X (right-extended) & Y (left-extended) to memory block */
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, words_mult);
mpi_to_mem_block(RSA_MEM_Z_BLOCK_BASE + words_mult * 4, Y, words_mult);
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words);
mpi_to_mem_block(RSA_MEM_Z_BLOCK_BASE + hw_words * 4, Y, hw_words);
/* NB: as Y is left-extended, we don't zero the bottom words_mult words of Y block.
This is OK for now because zeroing is done by hardware when we do esp_mpi_acquire_hardware().
*/
@ -540,17 +529,20 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
/* "mode" register loaded with number of 512-bit blocks in result,
plus 7 (for range 9-12). (this is ((N~ / 32) - 1) + 8))
*/
DPORT_REG_WRITE(RSA_MULT_MODE_REG, (words_z / 16) + 7);
DPORT_REG_WRITE(RSA_MULT_MODE_REG, ((hw_words * 2) / 16) + 7);
start_op(RSA_MULT_START_REG);
MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, z_words) );
wait_op_complete(RSA_MULT_START_REG);
/* Read back the result */
ret = mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, words_z);
mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, z_words);
Z->s = X->s * Y->s;
cleanup:
esp_mpi_release_hardware();
return ret;
@ -560,7 +552,7 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
multiplication to calculate an mbedtls_mpi_mult_mpi result where either
A or B are >2048 bits so can't use the standard multiplication method.
Result (A bits + B bits) must still be less than 4096 bits.
Result (z_words, based on A bits + B bits) must still be less than 4096 bits.
This case is simpler than the general case modulo multiply of
esp_mpi_mul_mpi_mod() because we can control the other arguments:
@ -573,29 +565,30 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
(See RSA Accelerator section in Technical Reference for more about Mprime, Rinv)
*/
static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words)
static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t z_words)
{
int ret = 0;
size_t hw_words = hardware_words(z_words);
/* Load coefficients to hardware */
esp_mpi_acquire_hardware();
/* M = 2^num_words - 1, so block is entirely FF */
for(int i = 0; i < num_words; i++) {
for(int i = 0; i < hw_words; i++) {
DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, UINT32_MAX);
}
/* Mprime = 1 */
DPORT_REG_WRITE(RSA_M_DASH_REG, 1);
/* "mode" register loaded with number of 512-bit blocks, minus 1 */
DPORT_REG_WRITE(RSA_MULT_MODE_REG, (num_words / 16) - 1);
DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hw_words / 16) - 1);
/* Load X */
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words);
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words);
/* Rinv = 1 */
DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE, 1);
for(int i = 1; i < num_words; i++) {
for(int i = 1; i < hw_words; i++) {
DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0);
}
@ -604,7 +597,7 @@ static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X,
wait_op_complete(RSA_MULT_START_REG);
/* finish the modular multiplication */
ret = modular_multiply_finish(Z, X, Y, num_words);
ret = modular_multiply_finish(Z, X, Y, hw_words, z_words);
esp_mpi_release_hardware();
@ -628,29 +621,28 @@ static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X,
Note that this function may recurse multiple times, if both X & Y
are too long for the hardware multiplication unit.
*/
static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t bits_y, size_t words_result)
static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t y_words, size_t z_words)
{
int ret = 0;
mbedtls_mpi Ztemp;
const size_t limbs_y = (bits_y + biL - 1) / biL;
/* Rather than slicing in two on bits we slice on limbs (32 bit words) */
const size_t limbs_slice = limbs_y / 2;
const size_t words_slice = y_words / 2;
/* Yp holds lower bits of Y (declared to reuse Y's array contents to save on copying) */
const mbedtls_mpi Yp = {
.p = Y->p,
.n = limbs_slice,
.n = words_slice,
.s = Y->s
};
/* Ypp holds upper bits of Y, right shifted (also reuses Y's array contents) */
const mbedtls_mpi Ypp = {
.p = Y->p + limbs_slice,
.n = limbs_y - limbs_slice,
.p = Y->p + words_slice,
.n = y_words - words_slice,
.s = Y->s
};
mbedtls_mpi_init(&Ztemp);
/* Grow Z to result size early, avoid interim allocations */
mbedtls_mpi_grow(Z, words_result);
mbedtls_mpi_grow(Z, z_words);
/* Get result Ztemp = Yp * X (need temporary variable Ztemp) */
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(&Ztemp, X, &Yp) );
@ -659,7 +651,7 @@ static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbe
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(Z, X, &Ypp) );
/* Z = Z << b */
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(Z, limbs_slice * biL) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(Z, words_slice * 32) );
/* Z += Ztemp */
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi(Z, Z, &Ztemp) );

View File

@ -0,0 +1,77 @@
/* mbedTLS Elliptic Curve functionality tests
Focus on testing functionality where we use ESP32 hardware
accelerated crypto features.
*/
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <esp_system.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecdh.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/error.h>
#include "unity.h"
/* Note: negative value here so that assert message prints a grep-able
error hex value (mbedTLS uses -N for error codes) */
#define TEST_ASSERT_MBEDTLS_OK(X) TEST_ASSERT_EQUAL_HEX32(0, -(X))
TEST_CASE("mbedtls ECDH Generate Key", "[mbedtls]")
{
mbedtls_ecdh_context ctx;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ecdh_init(&ctx);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
TEST_ASSERT_MBEDTLS_OK( mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0) );
TEST_ASSERT_MBEDTLS_OK( mbedtls_ecp_group_load(&ctx.grp, MBEDTLS_ECP_DP_CURVE25519) );
TEST_ASSERT_MBEDTLS_OK( mbedtls_ecdh_gen_public(&ctx.grp, &ctx.d, &ctx.Q,
mbedtls_ctr_drbg_random, &ctr_drbg ) );
mbedtls_ecdh_free(&ctx);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
}
TEST_CASE("mbedtls ECP self-tests", "[mbedtls]")
{
TEST_ASSERT_EQUAL(0, mbedtls_ecp_self_test(1));
}
TEST_CASE("mbedtls ECP mul w/ koblitz", "[mbedtls]")
{
/* Test case code via https://github.com/espressif/esp-idf/issues/1556 */
mbedtls_entropy_context ctxEntropy;
mbedtls_ctr_drbg_context ctxRandom;
mbedtls_ecdsa_context ctxECDSA;
const char* pers = "myecdsa";
mbedtls_entropy_init(&ctxEntropy);
mbedtls_ctr_drbg_init(&ctxRandom);
TEST_ASSERT_MBEDTLS_OK( mbedtls_ctr_drbg_seed(&ctxRandom, mbedtls_entropy_func, &ctxEntropy,
(const unsigned char*) pers, strlen(pers)) );
mbedtls_ecdsa_init(&ctxECDSA);
TEST_ASSERT_MBEDTLS_OK( mbedtls_ecdsa_genkey(&ctxECDSA, MBEDTLS_ECP_DP_SECP256K1,
mbedtls_ctr_drbg_random, &ctxRandom) );
TEST_ASSERT_MBEDTLS_OK(mbedtls_ecp_mul(&ctxECDSA.grp, &ctxECDSA.Q, &ctxECDSA.d, &ctxECDSA.grp.G,
mbedtls_ctr_drbg_random, &ctxRandom) );
mbedtls_ecdsa_free(&ctxECDSA);
mbedtls_ctr_drbg_free(&ctxRandom);
mbedtls_entropy_free(&ctxEntropy);
}

View File

@ -41,6 +41,10 @@ extern int _scanf_float(struct _reent *rptr,
FILE *fp,
va_list *ap);
static void raise_r_stub(struct _reent *rptr)
{
_raise_r(rptr, 0);
}
static struct syscall_stub_table s_stub_table = {
.__getreent = &__getreent,
@ -53,7 +57,7 @@ static struct syscall_stub_table s_stub_table = {
._rename_r = &esp_vfs_rename,
._times_r = &_times_r,
._gettimeofday_r = &_gettimeofday_r,
._raise_r = (void (*)(struct _reent *r)) &_raise_r,
._raise_r = &raise_r_stub,
._unlink_r = &esp_vfs_unlink,
._link_r = &esp_vfs_link,
._stat_r = &esp_vfs_stat,

View File

@ -5,7 +5,7 @@ Introduction
------------
:component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` utility is designed to help create a binary file, compatible with NVS architecture defined in :doc:`Non-Volatile Storage </api-reference/storage/nvs_flash>`, based on user provided key-value pairs in a CSV file.
Utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This helps manufacturers set unique value for various parameters for each device, e.g. serial number, while using same application firmaware for all devices.
Utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This helps manufacturers set unique value for various parameters for each device, e.g. serial number, while using same application firmware for all devices.
CSV file format
---------------
@ -49,9 +49,19 @@ When a new namespace entry is encountered in the CSV file, each follow-up entrie
Running the utility
-------------------
A sample CSV file provided with the utility. You can run the utility using below command::
You can run the utility using below command::
python nvs_partition_gen.py [-h] input output size
Positional arguments:
| Arguments | Description
| --- | ---
| input | Path to CSV file to parse. Will use stdin if omitted (a sample.csv is provided)
| output | Path to output converted binary file. Will use stdout if omitted
| size | Size of NVS Partition in KB. E.g. 12KB
python nvs_partition_generator.py sample.csv sample.bin
Caveats
-------

View File

@ -58,12 +58,13 @@ class Page(object):
ACTIVE = 0xFFFFFFFE
FULL = 0xFFFFFFFC
def __init__(self, page_num):
def __init__(self, page_num, is_rsrv_page=False):
self.entry_num = 0
self.bitmap_array = array.array('B')
self.page_buf = bytearray(b'\xff')*Page.PAGE_PARAMS["max_size"]
self.bitmap_array = self.create_bitmap_array()
self.set_header(page_num)
if not is_rsrv_page:
self.bitmap_array = self.create_bitmap_array()
self.set_header(page_num)
def set_header(self, page_num):
global page_header
@ -127,8 +128,8 @@ class Page(object):
chunk_size = 0
# Get the size available in current page
if self.entry_num < (Page.PAGE_PARAMS["max_entries"] - 1):
tailroom = (Page.PAGE_PARAMS["max_entries"] - self.entry_num - 1) * Page.SINGLE_ENTRY_SIZE
tailroom = (Page.PAGE_PARAMS["max_entries"] - self.entry_num - 1) * Page.SINGLE_ENTRY_SIZE
assert tailroom >=0, "Page overflow!!"
# Split the binary data into two and store a chunk of available size onto curr page
if tailroom < remaining_size:
@ -322,7 +323,8 @@ class Page(object):
NVS class encapsulates all NVS specific operations to create a binary with given key-value pairs. Binary can later be flashed onto device via a flashing utility.
"""
class NVS(object):
def __init__(self, fout):
def __init__(self, fout, input_size):
self.size = input_size
self.namespace_idx = 0
self.page_num = -1
self.pages = []
@ -334,12 +336,27 @@ class NVS(object):
def __exit__(self, exc_type, exc_value, traceback):
if exc_type == None and exc_value == None:
# Create pages for remaining available size
while True:
try:
new_page = self.create_new_page()
except InsufficientSizeError:
self.size = None
# Creating the last reserved page
self.create_new_page(True)
break
result = self.get_binary_data()
self.fout.write(result)
def create_new_page(self):
def create_new_page(self, is_rsrv_page=False):
# Update available size as each page is created
if self.size == 0:
raise InsufficientSizeError("Size parameter is is less than the size of data in csv.Please increase size.")
if not is_rsrv_page:
self.size = self.size - Page.PAGE_PARAMS["max_size"]
self.page_num += 1
new_page = Page(self.page_num)
new_page = Page(self.page_num, is_rsrv_page)
self.pages.append(new_page)
self.cur_page = new_page
return new_page
@ -418,13 +435,21 @@ class InputError(RuntimeError):
def __init__(self, e):
super(InputError, self).__init__(e)
def nvs_open(result_obj):
class InsufficientSizeError(RuntimeError):
"""
Represents error when NVS Partition size given is insufficient
to accomodate the data in the given csv file
"""
def __init__(self, e):
super(InsufficientSizeError, self).__init__(e)
def nvs_open(result_obj, input_size):
""" Wrapper to create and NVS class object. This object can later be used to set key-value pairs
:param result_obj: File/Stream object to dump resultant binary. If data is to be dumped into memory, one way is to use BytesIO object
:return: NVS class instance
"""
return NVS(result_obj)
return NVS(result_obj, input_size)
def write_entry(nvs_instance, key, datatype, encoding, value):
""" Wrapper to set key-value pair in NVS format
@ -457,16 +482,34 @@ def nvs_close(nvs_instance):
"""
nvs_instance.__exit__(None, None, None)
def nvs_part_gen(input_filename=None, output_filename=None):
def nvs_part_gen(input_filename=None, output_filename=None, input_size=None):
""" Wrapper to generate nvs partition binary
:param input_filename: Name of input file containing data
:param output_filename: Name of output file to store generated binary
:param input_size: Size of partition
:return: None
"""
if input_size % 4096 !=0:
sys.exit("Size parameter should be a multiple of 4KB.")
# Update size as a page needs to be reserved of size 4KB
input_size = input_size - Page.PAGE_PARAMS["max_size"]
if input_size == 0:
sys.exit("Size parameter is insufficient.")
input_file = open(input_filename, 'rb')
output_file = open(output_filename, 'wb')
with nvs_open(output_file) as nvs_obj:
with nvs_open(output_file, input_size) as nvs_obj:
# Update size as one page is created
#nvs_obj.size = input_size - Page.PAGE_PARAMS["max_size"]
reader = csv.DictReader(input_file, delimiter=',')
for row in reader:
try:
write_entry(nvs_obj, row["key"], row["type"], row["encoding"], row["value"])
except InputError as e:
except (InputError, InsufficientSizeError) as e:
print(e)
input_file.close()
output_file.close()
@ -487,10 +530,17 @@ def main():
help='Path to output converted binary file. Will use stdout if omitted',
default=sys.stdout)
parser.add_argument(
"size",
help='Size of NVS Partition in KB. Eg. 12KB')
args = parser.parse_args()
input_filename = args.input
output_filename = args.output
nvs_part_gen(input_filename, output_filename)
# Set size
input_size = int(args.size.split('KB')[0]) * 1024
nvs_part_gen(input_filename, output_filename, input_size)

View File

@ -180,6 +180,9 @@ esp_err_t Storage::writeMultiPageBlob(uint8_t nsIndex, const char* key, const vo
err = mPageManager.requestNewPage();
if (err != ESP_OK) {
return err;
} else if(getCurrentPage().getVarDataTailroom() == tailroom) {
/* We got the same page or we are not improving.*/
return ESP_ERR_NVS_NOT_ENOUGH_SPACE;
} else {
continue;
}
@ -257,7 +260,6 @@ esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key
err = findItem(nsIndex, datatype, key, findPage, item);
}
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) {
return err;
}
@ -280,6 +282,7 @@ esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key
}
/* Write the blob with new version*/
err = writeMultiPageBlob(nsIndex, key, data, dataSize, nextStart);
if (err == ESP_ERR_NVS_PAGE_FULL) {
return ESP_ERR_NVS_NOT_ENOUGH_SPACE;
}

View File

@ -1710,6 +1710,27 @@ TEST_CASE("Check that orphaned blobs are erased during init", "[nvs]")
TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, "key3", blob, sizeof(blob)));
}
TEST_CASE("nvs code handles errors properly when partition is near to full", "[nvs]")
{
const size_t blob_size = Page::CHUNK_MAX_SIZE * 0.3 ;
uint8_t blob[blob_size] = {0x11};
SpiFlashEmulator emu(5);
Storage storage;
char nvs_key[16] = "";
TEST_ESP_OK(storage.init(0, 5));
/* Four pages should fit roughly 12 blobs*/
for(uint8_t count = 1; count <= 12; count++) {
sprintf(nvs_key, "key:%u", count);
TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, nvs_key, blob, sizeof(blob)));
}
for(uint8_t count = 13; count <= 20; count++) {
sprintf(nvs_key, "key:%u", count);
TEST_ESP_ERR(storage.writeItem(1, ItemType::BLOB, nvs_key, blob, sizeof(blob)), ESP_ERR_NVS_NOT_ENOUGH_SPACE);
}
}
TEST_CASE("Check for nvs version incompatibility", "[nvs]")
{
@ -1977,7 +1998,8 @@ TEST_CASE("check partition generation utility", "[nvs_part_gen]")
exit(execlp("python", "python",
"../nvs_partition_generator/nvs_partition_gen.py",
"../nvs_partition_generator/sample.csv",
"../nvs_partition_generator/partition.bin", NULL));
"../nvs_partition_generator/partition.bin",
"12KB",NULL));
} else {
CHECK(childpid > 0);
int status;

View File

@ -56,7 +56,7 @@ else
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN)
endif
$(PARTITION_TABLE_BIN_UNSIGNED): $(PARTITION_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFILE)
$(PARTITION_TABLE_BIN_UNSIGNED): $(PARTITION_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFILE) | check_python_dependencies
@echo "Building partitions from $(PARTITION_TABLE_CSV_PATH)..."
$(GEN_ESP32PART) $< $@
@ -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
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
@echo "Partition flashing command:"
@echo "$(PARTITION_TABLE_FLASH_CMD)"
partition_table-flash: $(PARTITION_TABLE_BIN)
partition_table-flash: $(PARTITION_TABLE_BIN) check_python_dependencies
@echo "Flashing partition table..."
$(PARTITION_TABLE_FLASH_CMD)

View File

@ -4,3 +4,5 @@ SOC_NAME := esp32
COMPONENT_SRCDIRS := $(SOC_NAME) src/
COMPONENT_ADD_INCLUDEDIRS := $(SOC_NAME)/include include
-include $(COMPONENT_PATH)/$(SOC_NAME)/component.mk

View File

@ -0,0 +1 @@
esp32/rtc_clk.o: CFLAGS += -fno-jump-tables -fno-tree-switch-conversion

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