forked from espressif/esp-idf
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ccb4cf5b7 | ||
|
|
f8e24754d1 | ||
|
|
86975b7e8f | ||
|
|
c2bb7d7cd6 | ||
|
|
cc3ba7186f | ||
|
|
7d28c02fd5 | ||
|
|
3becdd7850 | ||
|
|
ef11260310 | ||
|
|
7b39d5e5c5 | ||
|
|
d5b0b36758 | ||
|
|
0a609be968 | ||
|
|
148a269808 | ||
|
|
5b11428f00 | ||
|
|
4cd7fd89f5 | ||
|
|
ceb56a7a72 | ||
|
|
ebfa74310c | ||
|
|
b482ba117d | ||
|
|
07735424a2 | ||
|
|
f2f5a237c0 | ||
|
|
3be1c70d46 | ||
|
|
beb34b5390 | ||
|
|
3991084777 | ||
|
|
088439c634 | ||
|
|
dbd05d8986 | ||
|
|
7c5dd19c83 | ||
|
|
a6fb161309 | ||
|
|
0929dbbc9b | ||
|
|
4c27f9ced8 | ||
|
|
b800dfe6f1 | ||
|
|
caa1ef0cb6 | ||
|
|
232408981d | ||
|
|
d7569b5862 | ||
|
|
db9979701a | ||
|
|
d54fadef41 | ||
|
|
3b4353da5d |
1088
.gitlab-ci.yml
1088
.gitlab-ci.yml
File diff suppressed because it is too large
Load Diff
@@ -141,3 +141,11 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t
|
||||
* @brief Configure VDDSDIO, call this API to rise VDDSDIO to 1.9V when VDDSDIO regulator is enabled as 1.8V mode.
|
||||
*/
|
||||
void bootloader_common_vddsdio_configure();
|
||||
|
||||
/**
|
||||
* @brief Set the flash CS setup and hold time.
|
||||
*
|
||||
* CS setup time is recomemded to be 1.5T, and CS hold time is recommended to be 2.5T.
|
||||
* cs_setup = 1, cs_setup_time = 0; cs_hold = 1, cs_hold_time = 1
|
||||
*/
|
||||
void bootloader_common_set_flash_cs_timing();
|
||||
|
||||
@@ -30,6 +30,13 @@
|
||||
bootloader_support components only.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get number of free pages
|
||||
*
|
||||
* @return Number of free pages
|
||||
*/
|
||||
uint32_t bootloader_mmap_get_free_pages();
|
||||
|
||||
/**
|
||||
* @brief Map a region of flash to data memory
|
||||
*
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "sys/param.h"
|
||||
@@ -274,3 +275,13 @@ void bootloader_common_vddsdio_configure()
|
||||
}
|
||||
#endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
|
||||
}
|
||||
|
||||
void bootloader_common_set_flash_cs_timing()
|
||||
{
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ static const char *TAG = "bootloader_mmap";
|
||||
|
||||
static spi_flash_mmap_handle_t map;
|
||||
|
||||
uint32_t bootloader_mmap_get_free_pages()
|
||||
{
|
||||
return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
|
||||
}
|
||||
|
||||
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
|
||||
{
|
||||
if (map) {
|
||||
@@ -91,12 +96,22 @@ static const char *TAG = "bootloader_flash";
|
||||
*/
|
||||
#define MMU_BLOCK0_VADDR 0x3f400000
|
||||
#define MMU_BLOCK50_VADDR 0x3f720000
|
||||
#define MMU_FREE_PAGES ((MMU_BLOCK50_VADDR - MMU_BLOCK0_VADDR) / FLASH_BLOCK_SIZE)
|
||||
|
||||
static bool mapped;
|
||||
|
||||
// Current bootloader mapping (ab)used for bootloader_read()
|
||||
static uint32_t current_read_mapping = UINT32_MAX;
|
||||
|
||||
uint32_t bootloader_mmap_get_free_pages()
|
||||
{
|
||||
/**
|
||||
* Allow mapping up to 50 of the 51 available MMU blocks (last one used for reads)
|
||||
* Since, bootloader_mmap function below assumes it to be 0x320000 (50 pages), we can safely do this.
|
||||
*/
|
||||
return MMU_FREE_PAGES;
|
||||
}
|
||||
|
||||
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
|
||||
{
|
||||
if (mapped) {
|
||||
|
||||
@@ -397,6 +397,9 @@ static void IRAM_ATTR flash_gpio_configure(const esp_image_header_t* pfhdr)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// improve the flash cs timing.
|
||||
bootloader_common_set_flash_cs_timing();
|
||||
}
|
||||
|
||||
static void uart_console_configure(void)
|
||||
|
||||
@@ -368,24 +368,22 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
uint32_t free_page_count = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
|
||||
ESP_LOGD(TAG, "free data page_count 0x%08x",free_page_count);
|
||||
uint32_t offset_page = 0;
|
||||
while (data_len >= free_page_count * SPI_FLASH_MMU_PAGE_SIZE) {
|
||||
offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0)?1:0;
|
||||
err = process_segment_data(load_addr, data_addr, (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE, do_load, sha_handle, checksum);
|
||||
uint32_t free_page_count = bootloader_mmap_get_free_pages();
|
||||
ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count);
|
||||
|
||||
int32_t data_len_remain = data_len;
|
||||
while (data_len_remain > 0) {
|
||||
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
|
||||
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
|
||||
data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
|
||||
err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
data_addr += (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE;
|
||||
data_len -= (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE;
|
||||
}
|
||||
#endif
|
||||
err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
data_addr += data_len;
|
||||
data_len_remain -= data_len;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
|
||||
@@ -21,12 +21,7 @@
|
||||
|
||||
#include "uECC.h"
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
#include "rom/sha.h"
|
||||
typedef SHA_CTX sha_context;
|
||||
#else
|
||||
#include "mbedtls/sha256.h"
|
||||
#endif
|
||||
#include <sys/param.h>
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
@@ -37,6 +32,9 @@ extern const uint8_t signature_verification_key_end[] asm("_binary_signature_ver
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
/* Mmap source address mask */
|
||||
#define MMAP_ALIGNED_MASK 0x0000FFFF
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
@@ -45,26 +43,44 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
data = bootloader_mmap(src_addr, length + sizeof(esp_secure_boot_sig_block_t));
|
||||
if(data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
bootloader_sha256_handle_t handle = bootloader_sha256_start();
|
||||
|
||||
uint32_t free_page_count = bootloader_mmap_get_free_pages();
|
||||
ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count);
|
||||
|
||||
int32_t data_len_remain = length;
|
||||
uint32_t data_addr = src_addr;
|
||||
while (data_len_remain > 0) {
|
||||
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
|
||||
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
|
||||
uint32_t data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
|
||||
data = (const uint8_t *) bootloader_mmap(data_addr, data_len);
|
||||
if(!data) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", data_addr, data_len);
|
||||
bootloader_sha256_finish(handle, NULL);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
bootloader_sha256_data(handle, data, data_len);
|
||||
bootloader_munmap(data);
|
||||
|
||||
data_addr += data_len;
|
||||
data_len_remain -= data_len;
|
||||
}
|
||||
|
||||
// Calculate digest of main image
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
bootloader_sha256_handle_t handle = bootloader_sha256_start();
|
||||
bootloader_sha256_data(handle, data, length);
|
||||
/* Done! Get the digest */
|
||||
bootloader_sha256_finish(handle, digest);
|
||||
#else
|
||||
/* Use thread-safe mbedTLS version */
|
||||
mbedtls_sha256_ret(data, length, digest, 0);
|
||||
#endif
|
||||
|
||||
// Map the signature block and verify the signature
|
||||
sigblock = (const esp_secure_boot_sig_block_t *)(data + length);
|
||||
// Map the signature block
|
||||
sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if(!sigblock) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// Verify the signature
|
||||
esp_err_t err = esp_secure_boot_verify_signature_block(sigblock, digest);
|
||||
bootloader_munmap(data);
|
||||
// Unmap
|
||||
bootloader_munmap(sigblock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
Submodule components/bt/lib updated: 031eaa576d...4b35933006
@@ -22,21 +22,34 @@
|
||||
#include "soc/soc.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "esp_ipc.h"
|
||||
|
||||
static const char* GPIO_TAG = "gpio";
|
||||
#define GPIO_CHECK(a, str, ret_val) \
|
||||
if (!(a)) { \
|
||||
ESP_LOGE(GPIO_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
|
||||
return (ret_val); \
|
||||
}
|
||||
#define GPIO_ISR_CORE_ID_UNINIT (3)
|
||||
|
||||
typedef struct {
|
||||
gpio_isr_t fn; /*!< isr function */
|
||||
void* args; /*!< isr function args */
|
||||
} gpio_isr_func_t;
|
||||
|
||||
// Used by the IPC call to register the interrupt service routine.
|
||||
typedef struct {
|
||||
int source; /*!< ISR source */
|
||||
int intr_alloc_flags; /*!< ISR alloc flag */
|
||||
void (*fn)(void*); /*!< ISR function */
|
||||
void *arg; /*!< ISR function args*/
|
||||
void *handle; /*!< ISR handle */
|
||||
esp_err_t ret;
|
||||
} gpio_isr_alloc_t;
|
||||
|
||||
static const char* GPIO_TAG = "gpio";
|
||||
static gpio_isr_func_t* gpio_isr_func = NULL;
|
||||
static gpio_isr_handle_t gpio_isr_handle;
|
||||
static uint32_t isr_core_id = GPIO_ISR_CORE_ID_UNINIT;
|
||||
static portMUX_TYPE gpio_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
esp_err_t gpio_pullup_en(gpio_num_t gpio_num)
|
||||
@@ -102,7 +115,6 @@ static void gpio_intr_status_clr(gpio_num_t gpio_num)
|
||||
|
||||
static esp_err_t gpio_intr_enable_on_core (gpio_num_t gpio_num, uint32_t core_id)
|
||||
{
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
gpio_intr_status_clr(gpio_num);
|
||||
if (core_id == 0) {
|
||||
GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr
|
||||
@@ -114,7 +126,13 @@ static esp_err_t gpio_intr_enable_on_core (gpio_num_t gpio_num, uint32_t core_id
|
||||
|
||||
esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
|
||||
{
|
||||
return gpio_intr_enable_on_core (gpio_num, xPortGetCoreID());
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&gpio_spinlock);
|
||||
if(isr_core_id == GPIO_ISR_CORE_ID_UNINIT) {
|
||||
isr_core_id = xPortGetCoreID();
|
||||
}
|
||||
portEXIT_CRITICAL(&gpio_spinlock);
|
||||
return gpio_intr_enable_on_core (gpio_num, isr_core_id);
|
||||
}
|
||||
|
||||
esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
|
||||
@@ -332,11 +350,9 @@ void IRAM_ATTR gpio_intr_service(void* arg)
|
||||
//GPIO intr process
|
||||
uint32_t gpio_num = 0;
|
||||
//read status to get interrupt status for GPIO0-31
|
||||
uint32_t gpio_intr_status;
|
||||
gpio_intr_status = GPIO.status;
|
||||
const uint32_t gpio_intr_status = (isr_core_id == 0) ? GPIO.pcpu_int : GPIO.acpu_int;
|
||||
//read status1 to get interrupt status for GPIO32-39
|
||||
uint32_t gpio_intr_status_h;
|
||||
gpio_intr_status_h = GPIO.status1.intr_st;
|
||||
const uint32_t gpio_intr_status_h = (isr_core_id == 0) ? GPIO.pcpu_int1.intr : GPIO.acpu_int1.intr;
|
||||
|
||||
if (gpio_isr_func == NULL) {
|
||||
return;
|
||||
@@ -395,12 +411,12 @@ esp_err_t gpio_install_isr_service(int intr_alloc_flags)
|
||||
esp_err_t ret;
|
||||
portENTER_CRITICAL(&gpio_spinlock);
|
||||
gpio_isr_func = (gpio_isr_func_t*) calloc(GPIO_NUM_MAX, sizeof(gpio_isr_func_t));
|
||||
portEXIT_CRITICAL(&gpio_spinlock);
|
||||
if (gpio_isr_func == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
} else {
|
||||
ret = gpio_isr_register(gpio_intr_service, NULL, intr_alloc_flags, &gpio_isr_handle);
|
||||
}
|
||||
portEXIT_CRITICAL(&gpio_spinlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -413,14 +429,37 @@ void gpio_uninstall_isr_service()
|
||||
esp_intr_free(gpio_isr_handle);
|
||||
free(gpio_isr_func);
|
||||
gpio_isr_func = NULL;
|
||||
isr_core_id = GPIO_ISR_CORE_ID_UNINIT;
|
||||
portEXIT_CRITICAL(&gpio_spinlock);
|
||||
return;
|
||||
}
|
||||
|
||||
static void gpio_isr_register_on_core_static(void *param)
|
||||
{
|
||||
gpio_isr_alloc_t *p = (gpio_isr_alloc_t *)param;
|
||||
//We need to check the return value.
|
||||
p->ret = esp_intr_alloc(p->source, p->intr_alloc_flags, p->fn, p->arg, p->handle);
|
||||
}
|
||||
|
||||
esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, gpio_isr_handle_t *handle)
|
||||
{
|
||||
GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG);
|
||||
return esp_intr_alloc(ETS_GPIO_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
|
||||
gpio_isr_alloc_t p;
|
||||
p.source = ETS_GPIO_INTR_SOURCE;
|
||||
p.intr_alloc_flags = intr_alloc_flags;
|
||||
p.fn = fn;
|
||||
p.arg = arg;
|
||||
p.handle = handle;
|
||||
portENTER_CRITICAL(&gpio_spinlock);
|
||||
if(isr_core_id == GPIO_ISR_CORE_ID_UNINIT) {
|
||||
isr_core_id = xPortGetCoreID();
|
||||
}
|
||||
portEXIT_CRITICAL(&gpio_spinlock);
|
||||
esp_err_t ret = esp_ipc_call_blocking(isr_core_id, gpio_isr_register_on_core_static, (void *)&p);
|
||||
if(ret != ESP_OK || p.ret != ESP_OK) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||
|
||||
@@ -1174,7 +1174,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de
|
||||
}
|
||||
if (send_ptr && isdma && !esp_ptr_dma_capable( send_ptr )) {
|
||||
//if txbuf in the desc not DMA-capable, malloc a new one
|
||||
ESP_LOGI( SPI_TAG, "Allocate TX buffer for DMA" );
|
||||
ESP_LOGD( SPI_TAG, "Allocate TX buffer for DMA" );
|
||||
uint32_t *temp = heap_caps_malloc((trans_desc->length + 7) / 8, MALLOC_CAP_DMA);
|
||||
if (temp == NULL) goto clean_up;
|
||||
|
||||
|
||||
@@ -616,3 +616,128 @@ TEST_CASE("GPIO drive capability test", "[gpio][ignore]")
|
||||
drive_capability_set_get(GPIO_OUTPUT_IO, GPIO_DRIVE_CAP_3);
|
||||
prompt_to_continue("If this test finishes");
|
||||
}
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
void gpio_enable_task(void *param)
|
||||
{
|
||||
int gpio_num = (int)param;
|
||||
TEST_ESP_OK(gpio_intr_enable(gpio_num));
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/** Test the GPIO Interrupt Enable API with dual core enabled. The GPIO ISR service routine is registered on one core.
|
||||
* When the GPIO interrupt on another core is enabled, the GPIO interrupt will be lost.
|
||||
* First on the core 0, Do the following steps:
|
||||
* 1. Configure the GPIO18 input_output mode, and enable the rising edge interrupt mode.
|
||||
* 2. Trigger the GPIO18 interrupt and check if the interrupt responds correctly.
|
||||
* 3. Disable the GPIO18 interrupt
|
||||
* Then on the core 1, Do the following steps:
|
||||
* 1. Enable the GPIO18 interrupt again.
|
||||
* 2. Trigger the GPIO18 interrupt and check if the interrupt responds correctly.
|
||||
*
|
||||
*/
|
||||
TEST_CASE("GPIO Enable/Disable interrupt on multiple cores", "[gpio][ignore]")
|
||||
{
|
||||
const int test_io18 = GPIO_NUM_18;
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
||||
io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << test_io18);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 1;
|
||||
TEST_ESP_OK(gpio_config(&io_conf));
|
||||
TEST_ESP_OK(gpio_set_level(test_io18, 0));
|
||||
TEST_ESP_OK(gpio_install_isr_service(0));
|
||||
TEST_ESP_OK(gpio_isr_handler_add(test_io18, gpio_isr_edge_handler, (void*) test_io18));
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(gpio_set_level(test_io18, 1));
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(gpio_set_level(test_io18, 0));
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(gpio_intr_disable(test_io18));
|
||||
TEST_ASSERT(edge_intr_times == 1);
|
||||
xTaskCreatePinnedToCore(gpio_enable_task, "gpio_enable_task", 1024*4, (void*)test_io18, 8, NULL, (xPortGetCoreID() == 0));
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(gpio_set_level(test_io18, 1));
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(gpio_set_level(test_io18, 0));
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(gpio_intr_disable(test_io18));
|
||||
TEST_ESP_OK(gpio_isr_handler_remove(test_io18));
|
||||
gpio_uninstall_isr_service();
|
||||
TEST_ASSERT(edge_intr_times == 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int gpio_num;
|
||||
int isr_cnt;
|
||||
} gpio_isr_param_t;
|
||||
|
||||
static void gpio_isr_handler(void* arg)
|
||||
{
|
||||
gpio_isr_param_t *param = (gpio_isr_param_t *)arg;
|
||||
ets_printf("GPIO[%d] intr, val: %d\n", param->gpio_num, gpio_get_level(param->gpio_num));
|
||||
param->isr_cnt++;
|
||||
}
|
||||
|
||||
/** The previous GPIO interrupt service routine polls the interrupt raw status register to find the GPIO that triggered the interrupt.
|
||||
* But this will incorrectly handle the interrupt disabled GPIOs, because the raw interrupt status register can still be set when
|
||||
* the trigger signal arrives, even if the interrupt is disabled.
|
||||
* First on the core 0:
|
||||
* 1. Configure the GPIO18 and GPIO19 input_output mode.
|
||||
* 2. Enable GPIO18 dual edge triggered interrupt, enable GPIO19 falling edge triggered interrupt.
|
||||
* 3. Trigger GPIO18 interrupt, then disable the GPIO8 interrupt, and then trigger GPIO18 again(This time will not respond to the interrupt).
|
||||
* 4. Trigger GPIO19 interrupt.
|
||||
* If the bug is not fixed, you will see, in the step 4, the interrupt of GPIO18 will also respond.
|
||||
*/
|
||||
TEST_CASE("GPIO ISR service test", "[gpio][ignore]")
|
||||
{
|
||||
const int test_io18 = GPIO_NUM_18;
|
||||
const int test_io19 = GPIO_NUM_19;
|
||||
static gpio_isr_param_t io18_param = {
|
||||
.gpio_num = GPIO_NUM_18,
|
||||
.isr_cnt = 0,
|
||||
};
|
||||
static gpio_isr_param_t io19_param = {
|
||||
.gpio_num = GPIO_NUM_19,
|
||||
.isr_cnt = 0,
|
||||
};
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << test_io18) | (1ULL << test_io19);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 1;
|
||||
TEST_ESP_OK(gpio_config(&io_conf));
|
||||
TEST_ESP_OK(gpio_set_level(test_io18, 0));
|
||||
TEST_ESP_OK(gpio_set_level(test_io19, 0));
|
||||
TEST_ESP_OK(gpio_install_isr_service(0));
|
||||
TEST_ESP_OK(gpio_set_intr_type(test_io18, GPIO_INTR_ANYEDGE));
|
||||
TEST_ESP_OK(gpio_set_intr_type(test_io19, GPIO_INTR_NEGEDGE));
|
||||
TEST_ESP_OK(gpio_isr_handler_add(test_io18, gpio_isr_handler, (void*)&io18_param));
|
||||
TEST_ESP_OK(gpio_isr_handler_add(test_io19, gpio_isr_handler, (void*)&io19_param));
|
||||
printf("Triggering the interrupt of GPIO18\n");
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
//Rising edge
|
||||
TEST_ESP_OK(gpio_set_level(test_io18, 1));
|
||||
printf("Disable the interrupt of GPIO18");
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
//Disable GPIO18 interrupt, GPIO18 will not respond to the next falling edge interrupt.
|
||||
TEST_ESP_OK(gpio_intr_disable(test_io18));
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
//Falling edge
|
||||
TEST_ESP_OK(gpio_set_level(test_io18, 0));
|
||||
|
||||
printf("Triggering the interrupt of GPIO19\n");
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(gpio_set_level(test_io19, 1));
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
//Falling edge
|
||||
TEST_ESP_OK(gpio_set_level(test_io19, 0));
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(gpio_isr_handler_remove(test_io18));
|
||||
TEST_ESP_OK(gpio_isr_handler_remove(test_io19));
|
||||
gpio_uninstall_isr_service();
|
||||
TEST_ASSERT((io18_param.isr_cnt == 1) && (io19_param.isr_cnt == 1));
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <assert.h>
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
// md5_digest_table 544d434da010ce22f7db1b14d38e1d66
|
||||
// md5_digest_table 2e23344575b3d07f01ecb695294e9770
|
||||
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
|
||||
// If you want to change some fields, you need to change esp_efuse_table.csv file
|
||||
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
|
||||
@@ -151,6 +151,10 @@ static const esp_efuse_desc_t CHIP_VER_REV1[] = {
|
||||
{EFUSE_BLK0, 111, 1}, // EFUSE_RD_CHIP_VER_REV1,
|
||||
};
|
||||
|
||||
static const esp_efuse_desc_t CHIP_VER_REV2[] = {
|
||||
{EFUSE_BLK0, 180, 1}, // EFUSE_RD_CHIP_VER_REV2,
|
||||
};
|
||||
|
||||
static const esp_efuse_desc_t XPD_SDIO_REG[] = {
|
||||
{EFUSE_BLK0, 142, 1}, // EFUSE_RD_XPD_SDIO_REG,
|
||||
};
|
||||
@@ -336,6 +340,11 @@ const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[] = {
|
||||
&CHIP_VER_REV2[0], // EFUSE_RD_CHIP_VER_REV2
|
||||
NULL
|
||||
};
|
||||
|
||||
const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[] = {
|
||||
&XPD_SDIO_REG[0], // EFUSE_RD_XPD_SDIO_REG
|
||||
NULL
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
##########################################################################
|
||||
# *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_MAX_BLK_LEN, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128.
|
||||
# !!!!!!!!!!! #
|
||||
# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table"
|
||||
# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table"
|
||||
# this will generate new source files, next rebuild all the sources.
|
||||
# !!!!!!!!!!! #
|
||||
|
||||
@@ -36,11 +36,11 @@ ABS_DONE_0, EFUSE_BLK0, 196, 1, Secure boot is enabled for
|
||||
ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, MAX_BLK_LEN, Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128)
|
||||
ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M
|
||||
|
||||
DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT.
|
||||
DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT.
|
||||
DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.
|
||||
DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.
|
||||
CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
|
||||
DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT.
|
||||
DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT.
|
||||
DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.
|
||||
DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.
|
||||
CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
|
||||
FLASH_CRYPT_CNT, EFUSE_BLK0, 20, 7, Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT.
|
||||
|
||||
# Write protection #
|
||||
@@ -53,7 +53,7 @@ WR_DIS_BLK3, EFUSE_BLK0, 9, 1, Write protection for EFUSE_B
|
||||
# Read protection #
|
||||
###################
|
||||
RD_DIS_BLK1, EFUSE_BLK0, 16, 1, Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1
|
||||
RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2
|
||||
RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2
|
||||
RD_DIS_BLK3, EFUSE_BLK0, 18, 1, Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3
|
||||
|
||||
# Chip info #
|
||||
@@ -64,6 +64,7 @@ CHIP_VER_PKG, EFUSE_BLK0, 105, 3, EFUSE_RD_CHIP_VER_PKG
|
||||
CHIP_CPU_FREQ_LOW, EFUSE_BLK0, 108, 1, EFUSE_RD_CHIP_CPU_FREQ_LOW
|
||||
CHIP_CPU_FREQ_RATED, EFUSE_BLK0, 109, 1, EFUSE_RD_CHIP_CPU_FREQ_RATED
|
||||
CHIP_VER_REV1, EFUSE_BLK0, 111, 1, EFUSE_RD_CHIP_VER_REV1
|
||||
CHIP_VER_REV2, EFUSE_BLK0, 180, 1, EFUSE_RD_CHIP_VER_REV2
|
||||
XPD_SDIO_REG, EFUSE_BLK0, 142, 1, EFUSE_RD_XPD_SDIO_REG
|
||||
SDIO_TIEH, EFUSE_BLK0, 143, 1, EFUSE_RD_SDIO_TIEH
|
||||
SDIO_FORCE, EFUSE_BLK0, 144, 1, EFUSE_RD_SDIO_FORCE
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 87.
|
@@ -17,7 +17,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// md5_digest_table 544d434da010ce22f7db1b14d38e1d66
|
||||
// md5_digest_table 2e23344575b3d07f01ecb695294e9770
|
||||
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
|
||||
// If you want to change some fields, you need to change esp_efuse_table.csv file
|
||||
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
|
||||
@@ -52,6 +52,7 @@ extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[];
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
|
||||
const static char *TAG = "efuse";
|
||||
|
||||
@@ -31,8 +32,29 @@ const static char *TAG = "efuse";
|
||||
// Returns chip version from efuse
|
||||
uint8_t esp_efuse_get_chip_ver(void)
|
||||
{
|
||||
uint8_t chip_ver;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &chip_ver, 1);
|
||||
uint8_t eco_bit0, eco_bit1, eco_bit2;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &eco_bit0, 1);
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV2, &eco_bit1, 1);
|
||||
eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 80000000) >> 31;
|
||||
uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
|
||||
uint8_t chip_ver = 0;
|
||||
switch (combine_value) {
|
||||
case 0:
|
||||
chip_ver = 0;
|
||||
break;
|
||||
case 1:
|
||||
chip_ver = 1;
|
||||
break;
|
||||
case 3:
|
||||
chip_ver = 2;
|
||||
break;
|
||||
case 7:
|
||||
chip_ver = 3;
|
||||
break;
|
||||
default:
|
||||
chip_ver = 0;
|
||||
break;
|
||||
}
|
||||
return chip_ver;
|
||||
}
|
||||
|
||||
@@ -111,7 +133,7 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
|
||||
ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]);
|
||||
REG_WRITE(blk_wdata0_reg + 4*i, buf[i]);
|
||||
REG_WRITE(blk_wdata0_reg + 4 * i, buf[i]);
|
||||
}
|
||||
bzero(buf, sizeof(buf));
|
||||
bzero(raw, sizeof(raw));
|
||||
|
||||
@@ -6,6 +6,34 @@ menu "ESP32-specific"
|
||||
default "y" if IDF_TARGET="esp32"
|
||||
default "n"
|
||||
|
||||
choice ESP32_REV_MIN
|
||||
prompt "Minimum Supported ESP32 Revision"
|
||||
default ESP32_REV_MIN_0
|
||||
help
|
||||
Minimum revision that ESP-IDF would support.
|
||||
ESP-IDF performs different strategy on different esp32 revision.
|
||||
|
||||
config ESP32_REV_MIN_0
|
||||
bool "Rev 0"
|
||||
config ESP32_REV_MIN_1
|
||||
bool "Rev 1"
|
||||
config ESP32_REV_MIN_2
|
||||
bool "Rev 2"
|
||||
config ESP32_REV_MIN_3
|
||||
bool "Rev 3"
|
||||
endchoice
|
||||
|
||||
config ESP32_REV_MIN
|
||||
int
|
||||
default 0 if ESP32_REV_MIN_0
|
||||
default 1 if ESP32_REV_MIN_1
|
||||
default 2 if ESP32_REV_MIN_2
|
||||
default 3 if ESP32_REV_MIN_3
|
||||
|
||||
config ESP32_DPORT_WORKAROUND
|
||||
bool
|
||||
default "y" if !FREERTOS_UNICORE && ESP32_REV_MIN < 2
|
||||
|
||||
choice ESP32_DEFAULT_CPU_FREQ_MHZ
|
||||
prompt "CPU frequency"
|
||||
default ESP32_DEFAULT_CPU_FREQ_160
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#include "pm_impl.h"
|
||||
#include "trax.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "bootloader_common.h"
|
||||
|
||||
#define STRINGIFY(s) STRINGIFY2(s)
|
||||
#define STRINGIFY2(s) #s
|
||||
@@ -173,6 +174,8 @@ void IRAM_ATTR call_start_cpu0()
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
# else // If psram is uninitialized, we need to improve the flash cs timing.
|
||||
bootloader_common_set_flash_cs_timing();
|
||||
#endif
|
||||
|
||||
ESP_EARLY_LOGI(TAG, "Pro cpu up.");
|
||||
@@ -390,6 +393,16 @@ void start_cpu0_default(void)
|
||||
spi_flash_init();
|
||||
/* init default OS-aware flash access critical section */
|
||||
spi_flash_guard_set(&g_flash_guard_default_ops);
|
||||
|
||||
uint8_t revision = esp_efuse_get_chip_ver();
|
||||
ESP_LOGI(TAG, "Chip Revision: %d", revision);
|
||||
if (revision > CONFIG_ESP32_REV_MIN) {
|
||||
ESP_LOGW(TAG, "Chip revision is higher than the one configured in menuconfig. Suggest to upgrade it.");
|
||||
} else if(revision != CONFIG_ESP32_REV_MIN) {
|
||||
ESP_LOGE(TAG, "ESP-IDF can't support this chip revision. Modify minimum supported revision in menuconfig");
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_impl_init();
|
||||
#ifdef CONFIG_PM_DFS_INIT_AUTO
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* DPORT access is used for do protection when dual core access DPORT internal register and APB register via DPORT simultaneously
|
||||
* This function will be initialize after FreeRTOS startup.
|
||||
* When cpu0 want to access DPORT register, it should notify cpu1 enter in high-priority interrupt for be mute. When cpu1 already in high-priority interrupt,
|
||||
* cpu0 can access DPORT register. Currently, cpu1 will wait for cpu0 finish access and exit high-priority interrupt.
|
||||
* cpu0 can access DPORT register. Currently, cpu1 will wait for cpu0 finish access and exit high-priority interrupt.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -116,7 +116,7 @@ void IRAM_ATTR esp_dport_access_stall_other_cpu_end(void)
|
||||
{
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
int cpu_id = xPortGetCoreID();
|
||||
|
||||
|
||||
if (dport_core_state[0] == DPORT_CORE_STATE_IDLE
|
||||
|| dport_core_state[1] == DPORT_CORE_STATE_IDLE) {
|
||||
return;
|
||||
@@ -249,7 +249,7 @@ void IRAM_ATTR esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address
|
||||
*/
|
||||
uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
uint32_t apb;
|
||||
@@ -295,7 +295,7 @@ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
|
||||
*/
|
||||
uint32_t IRAM_ATTR esp_dport_access_sequence_reg_read(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
uint32_t apb;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <string.h>
|
||||
#include "mbedtls/aes.h"
|
||||
#include "hwcrypto/aes.h"
|
||||
#include "mbedtls/platform_util.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/hwcrypto_reg.h"
|
||||
#include <sys/lock.h>
|
||||
@@ -49,6 +50,11 @@
|
||||
*/
|
||||
static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static inline bool valid_key_length(const esp_aes_context *ctx)
|
||||
{
|
||||
return ctx->key_bytes == 128/8 || ctx->key_bytes == 192/8 || ctx->key_bytes == 256/8;
|
||||
}
|
||||
|
||||
void esp_aes_acquire_hardware( void )
|
||||
{
|
||||
portENTER_CRITICAL(&aes_spinlock);
|
||||
@@ -93,6 +99,7 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key,
|
||||
}
|
||||
ctx->key_bytes = keybits / 8;
|
||||
memcpy(ctx->key, key, ctx->key_bytes);
|
||||
ctx->key_in_hardware = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -102,35 +109,83 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key,
|
||||
*
|
||||
* Call only while holding esp_aes_acquire_hardware().
|
||||
*/
|
||||
static inline void esp_aes_setkey_hardware( esp_aes_context *ctx, int mode)
|
||||
static void esp_aes_setkey_hardware(esp_aes_context *ctx, int mode)
|
||||
{
|
||||
const uint32_t MODE_DECRYPT_BIT = 4;
|
||||
unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT;
|
||||
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
for (int i = 0; i < ctx->key_bytes/4; ++i) {
|
||||
DPORT_REG_WRITE(AES_KEY_BASE + i * 4, *(((uint32_t *)ctx->key) + i));
|
||||
ctx->key_in_hardware += 4;
|
||||
}
|
||||
|
||||
DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2));
|
||||
|
||||
/* Fault injection check: all words of key data should have been written to hardware */
|
||||
if (ctx->key_in_hardware < 16
|
||||
|| ctx->key_in_hardware != ctx->key_bytes) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Run a single 16 byte block of AES, using the hardware engine.
|
||||
*
|
||||
* Call only while holding esp_aes_acquire_hardware().
|
||||
*/
|
||||
static inline void esp_aes_block(const void *input, void *output)
|
||||
static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output)
|
||||
{
|
||||
const uint32_t *input_words = (const uint32_t *)input;
|
||||
uint32_t i0, i1, i2, i3;
|
||||
uint32_t *output_words = (uint32_t *)output;
|
||||
uint32_t *mem_block = (uint32_t *)AES_TEXT_BASE;
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
mem_block[i] = input_words[i];
|
||||
/* If no key is written to hardware yet, either the user hasn't called
|
||||
mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec - meaning we also don't
|
||||
know which mode to use - or a fault skipped the
|
||||
key write to hardware. Treat this as a fatal error and zero the output block.
|
||||
*/
|
||||
if (ctx->key_in_hardware != ctx->key_bytes) {
|
||||
bzero(output, 16);
|
||||
return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
|
||||
}
|
||||
|
||||
/* Storing i0,i1,i2,i3 in registers not an array
|
||||
helps a lot with optimisations at -Os level */
|
||||
i0 = input_words[0];
|
||||
DPORT_REG_WRITE(AES_TEXT_BASE, i0);
|
||||
|
||||
i1 = input_words[1];
|
||||
DPORT_REG_WRITE(AES_TEXT_BASE + 4, i1);
|
||||
|
||||
i2 = input_words[2];
|
||||
DPORT_REG_WRITE(AES_TEXT_BASE + 8, i2);
|
||||
|
||||
i3 = input_words[3];
|
||||
DPORT_REG_WRITE(AES_TEXT_BASE + 12, i3);
|
||||
|
||||
DPORT_REG_WRITE(AES_START_REG, 1);
|
||||
|
||||
while (DPORT_REG_READ(AES_IDLE_REG) != 1) { }
|
||||
esp_dport_access_read_buffer(output_words, (uint32_t)&mem_block[0], 4);
|
||||
|
||||
esp_dport_access_read_buffer(output_words, AES_TEXT_BASE, 4);
|
||||
|
||||
/* Physical security check: Verify the AES accelerator actually ran, and wasn't
|
||||
skipped due to external fault injection while starting the peripheral.
|
||||
|
||||
Note that i0,i1,i2,i3 are copied from input buffer in case input==output.
|
||||
|
||||
Bypassing this check requires at least one additional fault.
|
||||
*/
|
||||
if(i0 == output_words[0] && i1 == output_words[1] && i2 == output_words[2] && i3 == output_words[3]) {
|
||||
// calling zeroing functions to narrow the
|
||||
// window for a double-fault of the abort step, here
|
||||
memset(output, 0, 16);
|
||||
mbedtls_platform_zeroize(output, 16);
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -140,11 +195,18 @@ int esp_internal_aes_encrypt( esp_aes_context *ctx,
|
||||
const unsigned char input[16],
|
||||
unsigned char output[16] )
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
esp_aes_block(input, output);
|
||||
r = esp_aes_block(ctx, input, output);
|
||||
esp_aes_release_hardware();
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void esp_aes_encrypt( esp_aes_context *ctx,
|
||||
@@ -162,11 +224,18 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx,
|
||||
const unsigned char input[16],
|
||||
unsigned char output[16] )
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT);
|
||||
esp_aes_block(input, output);
|
||||
r = esp_aes_block(ctx, input, output);
|
||||
esp_aes_release_hardware();
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void esp_aes_decrypt( esp_aes_context *ctx,
|
||||
@@ -176,7 +245,6 @@ void esp_aes_decrypt( esp_aes_context *ctx,
|
||||
esp_internal_aes_decrypt(ctx, input, output);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AES-ECB block encryption/decryption
|
||||
*/
|
||||
@@ -185,12 +253,19 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx,
|
||||
const unsigned char input[16],
|
||||
unsigned char output[16] )
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
esp_aes_setkey_hardware(ctx, mode);
|
||||
esp_aes_block(input, output);
|
||||
r = esp_aes_block(ctx, input, output);
|
||||
esp_aes_release_hardware();
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,14 +289,19 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx,
|
||||
return ( ERR_ESP_AES_INVALID_INPUT_LENGTH );
|
||||
}
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
esp_aes_setkey_hardware(ctx, mode);
|
||||
|
||||
if ( mode == ESP_AES_DECRYPT ) {
|
||||
while ( length > 0 ) {
|
||||
memcpy(temp, input_words, 16);
|
||||
esp_aes_block(input_words, output_words);
|
||||
esp_aes_block(ctx, input_words, output_words);
|
||||
|
||||
for ( i = 0; i < 4; i++ ) {
|
||||
output_words[i] = output_words[i] ^ iv_words[i];
|
||||
@@ -240,7 +320,7 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx,
|
||||
output_words[i] = input_words[i] ^ iv_words[i];
|
||||
}
|
||||
|
||||
esp_aes_block(output_words, output_words);
|
||||
esp_aes_block(ctx, output_words, output_words);
|
||||
memcpy( iv_words, output_words, 16 );
|
||||
|
||||
input_words += 4;
|
||||
@@ -268,14 +348,19 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx,
|
||||
int c;
|
||||
size_t n = *iv_off;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
|
||||
if ( mode == ESP_AES_DECRYPT ) {
|
||||
while ( length-- ) {
|
||||
if ( n == 0 ) {
|
||||
esp_aes_block(iv, iv );
|
||||
esp_aes_block(ctx, iv, iv );
|
||||
}
|
||||
|
||||
c = *input++;
|
||||
@@ -287,7 +372,7 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx,
|
||||
} else {
|
||||
while ( length-- ) {
|
||||
if ( n == 0 ) {
|
||||
esp_aes_block(iv, iv );
|
||||
esp_aes_block(ctx, iv, iv );
|
||||
}
|
||||
|
||||
iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
|
||||
@@ -316,13 +401,18 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx,
|
||||
unsigned char c;
|
||||
unsigned char ov[17];
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
|
||||
while ( length-- ) {
|
||||
memcpy( ov, iv, 16 );
|
||||
esp_aes_block(iv, iv);
|
||||
esp_aes_block(ctx, iv, iv);
|
||||
|
||||
if ( mode == ESP_AES_DECRYPT ) {
|
||||
ov[16] = *input;
|
||||
@@ -356,13 +446,18 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx,
|
||||
int c, i;
|
||||
size_t n = *nc_off;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
|
||||
while ( length-- ) {
|
||||
if ( n == 0 ) {
|
||||
esp_aes_block(nonce_counter, stream_block);
|
||||
esp_aes_block(ctx, nonce_counter, stream_block);
|
||||
|
||||
for ( i = 16; i > 0; i-- )
|
||||
if ( ++nonce_counter[i - 1] != 0 ) {
|
||||
|
||||
@@ -226,6 +226,9 @@ void esp_sha_wait_idle(void)
|
||||
|
||||
void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
|
||||
{
|
||||
uint32_t *digest_state_words = NULL;
|
||||
uint32_t *reg_addr_buf = NULL;
|
||||
uint32_t word_len = sha_length(sha_type)/4;
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
SemaphoreHandle_t *engine_state = sha_get_engine_state(sha_type);
|
||||
@@ -243,20 +246,30 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
|
||||
|
||||
DPORT_REG_WRITE(SHA_LOAD_REG(sha_type), 1);
|
||||
while(DPORT_REG_READ(SHA_BUSY_REG(sha_type)) == 1) { }
|
||||
uint32_t *digest_state_words = (uint32_t *)digest_state;
|
||||
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
|
||||
digest_state_words = (uint32_t *)digest_state;
|
||||
reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
|
||||
if(sha_type == SHA2_384 || sha_type == SHA2_512) {
|
||||
/* for these ciphers using 64-bit states, swap each pair of words */
|
||||
DPORT_INTERRUPT_DISABLE(); // Disable interrupt only on current CPU.
|
||||
for(int i = 0; i < sha_length(sha_type)/4; i += 2) {
|
||||
for(int i = 0; i < word_len; i += 2) {
|
||||
digest_state_words[i+1] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i]);
|
||||
digest_state_words[i] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i+1]);
|
||||
}
|
||||
DPORT_INTERRUPT_RESTORE(); // restore the previous interrupt level
|
||||
} else {
|
||||
esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], sha_length(sha_type)/4);
|
||||
esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], word_len);
|
||||
}
|
||||
esp_sha_unlock_memory_block();
|
||||
|
||||
/* Fault injection check: verify SHA engine actually ran,
|
||||
state is not all zeroes.
|
||||
*/
|
||||
for (int i = 0; i < word_len; i++) {
|
||||
if (digest_state_words[i] != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
abort(); // SHA peripheral returned all zero state, probably due to fault injection
|
||||
}
|
||||
|
||||
void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block)
|
||||
@@ -310,6 +323,8 @@ void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, uns
|
||||
|
||||
esp_sha_lock_engine(sha_type);
|
||||
|
||||
bzero(output, sha_length(sha_type));
|
||||
|
||||
SHA_CTX ctx;
|
||||
ets_sha_init(&ctx);
|
||||
|
||||
@@ -353,4 +368,14 @@ void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, uns
|
||||
}
|
||||
|
||||
esp_sha_unlock_engine(sha_type);
|
||||
|
||||
/* Fault injection check: verify SHA engine actually ran,
|
||||
state is not all zeroes.
|
||||
*/
|
||||
for (int i = 0; i < sha_length(sha_type); i++) {
|
||||
if (output[i] != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
abort(); // SHA peripheral returned all zero state, probably due to fault injection
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ uint32_t esp_dport_access_sequence_reg_read(uint32_t reg);
|
||||
//only call in case of panic().
|
||||
void esp_dport_access_int_abort(void);
|
||||
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
#define DPORT_STALL_OTHER_CPU_START()
|
||||
#define DPORT_STALL_OTHER_CPU_END()
|
||||
#define DPORT_INTERRUPT_DISABLE()
|
||||
|
||||
@@ -41,17 +41,13 @@ extern "C" {
|
||||
/**
|
||||
* \brief AES context structure
|
||||
*
|
||||
* \note buf is able to hold 32 extra bytes, which can be used:
|
||||
* - for alignment purposes if VIA padlock is used, and/or
|
||||
* - to simplify key expansion in the 256-bit case by
|
||||
* generating an extra round key
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_bytes;
|
||||
volatile uint8_t key_in_hardware; /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */
|
||||
uint8_t key[32];
|
||||
} esp_aes_context;
|
||||
|
||||
|
||||
/**
|
||||
* \brief The AES XTS context-type definition.
|
||||
*/
|
||||
|
||||
@@ -511,6 +511,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t
|
||||
spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN;
|
||||
} else if (rd_mode_reg & SPI_FREAD_DIO_M) {
|
||||
spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S);
|
||||
} else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) {
|
||||
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
|
||||
} else {
|
||||
|
||||
@@ -205,7 +205,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type)
|
||||
ESP_LOGW(TAG, "incorrect mac type");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -296,10 +296,10 @@ void IRAM_ATTR esp_restart_noos()
|
||||
WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30);
|
||||
|
||||
// Reset wifi/bluetooth/ethernet/sdio (bb/mac)
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG,
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG,
|
||||
DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST |
|
||||
DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST |
|
||||
DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST |
|
||||
DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST |
|
||||
DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST);
|
||||
DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0);
|
||||
|
||||
@@ -355,35 +355,27 @@ const char* esp_get_idf_version(void)
|
||||
return IDF_VER;
|
||||
}
|
||||
|
||||
static void get_chip_info_esp32(esp_chip_info_t* out_info)
|
||||
void esp_chip_info(esp_chip_info_t* out_info)
|
||||
{
|
||||
uint32_t reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
|
||||
uint32_t efuse_rd3 = REG_READ(EFUSE_BLK0_RDATA3_REG);
|
||||
memset(out_info, 0, sizeof(*out_info));
|
||||
|
||||
|
||||
out_info->model = CHIP_ESP32;
|
||||
if ((reg & EFUSE_RD_CHIP_VER_REV1_M) != 0) {
|
||||
out_info->revision = 1;
|
||||
}
|
||||
if ((reg & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) {
|
||||
out_info->revision = esp_efuse_get_chip_ver();
|
||||
|
||||
if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) {
|
||||
out_info->cores = 2;
|
||||
} else {
|
||||
out_info->cores = 1;
|
||||
}
|
||||
out_info->features = CHIP_FEATURE_WIFI_BGN;
|
||||
if ((reg & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) {
|
||||
if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) {
|
||||
out_info->features |= CHIP_FEATURE_BT | CHIP_FEATURE_BLE;
|
||||
}
|
||||
int package = (reg & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S;
|
||||
int package = (efuse_rd3 & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S;
|
||||
if (package == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 ||
|
||||
package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 ||
|
||||
package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
|
||||
out_info->features |= CHIP_FEATURE_EMB_FLASH;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_chip_info(esp_chip_info_t* out_info)
|
||||
{
|
||||
// Only ESP32 is supported now, in the future call one of the
|
||||
// chip-specific functions based on sdkconfig choice
|
||||
return get_chip_info_esp32(out_info);
|
||||
}
|
||||
|
||||
@@ -297,6 +297,26 @@ esp_err_t esp_http_client_delete_header(esp_http_client_handle_t client, const c
|
||||
return http_header_delete(client->request->headers, key);
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **value)
|
||||
{
|
||||
if (client == NULL || value == NULL) {
|
||||
ESP_LOGE(TAG, "client or value must not be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
*value = client->connection_info.username;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **value)
|
||||
{
|
||||
if (client == NULL || value == NULL) {
|
||||
ESP_LOGE(TAG, "client or value must not be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
*value = client->connection_info.password;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_client_config_t *config)
|
||||
{
|
||||
client->connection_info.method = config->method;
|
||||
@@ -677,7 +697,10 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
|
||||
}
|
||||
old_port = client->connection_info.port;
|
||||
|
||||
if (purl.field_data[UF_HOST].len) {
|
||||
// Whether the passed url is absolute or is just a path
|
||||
bool is_absolute_url = (bool) purl.field_data[UF_HOST].len;
|
||||
|
||||
if (is_absolute_url) {
|
||||
http_utils_assign_string(&client->connection_info.host, url + purl.field_data[UF_HOST].off, purl.field_data[UF_HOST].len);
|
||||
HTTP_MEM_CHECK(TAG, client->connection_info.host, return ESP_ERR_NO_MEM);
|
||||
}
|
||||
@@ -734,7 +757,8 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
|
||||
} else {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
} else {
|
||||
} else if (is_absolute_url) {
|
||||
// Only reset authentication info if the passed URL is full
|
||||
free(client->connection_info.username);
|
||||
free(client->connection_info.password);
|
||||
client->connection_info.username = NULL;
|
||||
@@ -1136,7 +1160,7 @@ esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len)
|
||||
return err;
|
||||
}
|
||||
if ((err = esp_http_client_request_send(client, write_len)) != ESP_OK) {
|
||||
return err;
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -235,13 +235,43 @@ esp_err_t esp_http_client_set_header(esp_http_client_handle_t client, const char
|
||||
*/
|
||||
esp_err_t esp_http_client_get_header(esp_http_client_handle_t client, const char *key, char **value);
|
||||
|
||||
/**
|
||||
* @brief Get http request username.
|
||||
* The address of username buffer will be assigned to value parameter.
|
||||
* This function must be called after `esp_http_client_init`.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[out] value The username value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **value);
|
||||
|
||||
/**
|
||||
* @brief Get http request password.
|
||||
* The address of password buffer will be assigned to value parameter.
|
||||
* This function must be called after `esp_http_client_init`.
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[out] value The password value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **value);
|
||||
|
||||
/**
|
||||
* @brief Set http request method
|
||||
*
|
||||
* @param[in] client The esp_http_client handle
|
||||
* @param[in] method The method
|
||||
*
|
||||
* @return ESP_OK
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t esp_http_client_set_method(esp_http_client_handle_t client, esp_http_client_method_t method);
|
||||
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
TEST_CASE("Input Param Tests", "[ESP HTTP CLIENT]")
|
||||
#define HOST "httpbin.org"
|
||||
#define USERNAME "user"
|
||||
#define PASSWORD "challenge"
|
||||
|
||||
TEST_CASE("Test in common case: Only URL and hostname are specified.", "[ESP HTTP CLIENT]")
|
||||
{
|
||||
esp_http_client_config_t config_incorrect = {0};
|
||||
|
||||
@@ -38,10 +42,88 @@ TEST_CASE("Input Param Tests", "[ESP HTTP CLIENT]")
|
||||
|
||||
|
||||
esp_http_client_config_t config_with_hostname_path = {
|
||||
.host = "httpbin.org",
|
||||
.host = HOST,
|
||||
.path = "/get",
|
||||
};
|
||||
client = esp_http_client_init(&config_with_hostname_path);
|
||||
TEST_ASSERT(client != NULL);
|
||||
TEST_ASSERT(esp_http_client_cleanup(client) == ESP_OK);
|
||||
}
|
||||
|
||||
TEST_CASE("Get username and password after initialization.", "[ESP HTTP CLIENT]")
|
||||
{
|
||||
esp_http_client_config_t config_with_auth = {
|
||||
.host = HOST,
|
||||
.path = "/",
|
||||
.username = USERNAME,
|
||||
.password = PASSWORD
|
||||
};
|
||||
char *value = NULL;
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config_with_auth);
|
||||
TEST_ASSERT_NOT_NULL(client);
|
||||
// Test with username
|
||||
esp_err_t r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
|
||||
// Test with password
|
||||
value = NULL;
|
||||
r = esp_http_client_get_password(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(PASSWORD, value);
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case to test that, the esp_http_client_set_url won't drop username and password
|
||||
* when pass a path "/abc" for url.
|
||||
**/
|
||||
TEST_CASE("Username is unmodified when we change to new path", "[ESP HTTP CLIENT]")
|
||||
{
|
||||
esp_http_client_config_t config_with_auth = {
|
||||
.host = HOST,
|
||||
.path = "/",
|
||||
.username = USERNAME,
|
||||
.password = PASSWORD
|
||||
};
|
||||
char *value = NULL;
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config_with_auth);
|
||||
TEST_ASSERT_NOT_NULL(client);
|
||||
esp_err_t r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
|
||||
esp_http_client_set_url(client, "/something-else/");
|
||||
r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case to test that, the esp_http_client_set_url will reset username and password
|
||||
* when passing a full URL with username & password missing.
|
||||
**/
|
||||
TEST_CASE("Username is reset if new absolute URL doesnot specify username.", "[ESP HTTP CLIENT]")
|
||||
{
|
||||
esp_http_client_config_t config_with_auth = {
|
||||
.host = HOST,
|
||||
.path = "/",
|
||||
.username = USERNAME,
|
||||
.password = PASSWORD
|
||||
};
|
||||
char *value = NULL;
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config_with_auth);
|
||||
TEST_ASSERT_NOT_NULL(client);
|
||||
esp_err_t r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NOT_NULL(value);
|
||||
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
|
||||
esp_http_client_set_url(client, "http://" HOST "/get");
|
||||
r = esp_http_client_get_username(client, &value);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, r);
|
||||
TEST_ASSERT_NULL(value);
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
Submodule components/esptool_py/esptool updated: 9ad444a6e0...1a7dbf787e
@@ -2464,12 +2464,11 @@ BaseType_t xSwitchRequired = pdFALSE;
|
||||
Increments the tick then checks to see if the new tick value will cause any
|
||||
tasks to be unblocked. */
|
||||
|
||||
/* Only let core 0 increase the tick count, to keep accurate track of time. */
|
||||
/* ToDo: This doesn't really play nice with the logic below: it means when core 1 is
|
||||
running a low-priority task, it will keep running it until there is a context
|
||||
switch, even when this routine (running on core 0) unblocks a bunch of high-priority
|
||||
tasks... this is less than optimal -- JD. */
|
||||
if ( xPortGetCoreID()!=0 ) {
|
||||
/* Only allow core 0 increase the tick count in the case of xPortSysTickHandler processing. */
|
||||
/* And allow core 0 and core 1 to unwind uxPendedTicks during xTaskResumeAll. */
|
||||
|
||||
if ( xPortInIsrContext() )
|
||||
{
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
vApplicationTickHook();
|
||||
#endif /* configUSE_TICK_HOOK */
|
||||
@@ -2477,11 +2476,10 @@ BaseType_t xSwitchRequired = pdFALSE;
|
||||
esp_vApplicationTickHook();
|
||||
#endif /* CONFIG_FREERTOS_LEGACY_HOOKS */
|
||||
|
||||
/*
|
||||
We can't really calculate what we need, that's done on core 0... just assume we need a switch.
|
||||
ToDo: Make this more intelligent? -- JD
|
||||
*/
|
||||
return pdTRUE;
|
||||
if (xPortGetCoreID() == 1 )
|
||||
{
|
||||
return pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2606,39 +2604,11 @@ BaseType_t xSwitchRequired = pdFALSE;
|
||||
}
|
||||
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
|
||||
|
||||
{
|
||||
/* Guard against the tick hook being called when the pended tick
|
||||
count is being unwound (when the scheduler is being unlocked). */
|
||||
if( uxPendedTicks == ( UBaseType_t ) 0U )
|
||||
{
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
vApplicationTickHook();
|
||||
#endif /* configUSE_TICK_HOOK */
|
||||
#if ( CONFIG_FREERTOS_LEGACY_HOOKS == 1 )
|
||||
esp_vApplicationTickHook();
|
||||
#endif /* CONFIG_FREERTOS_LEGACY_HOOKS */
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL_ISR(&xTaskQueueMutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
++uxPendedTicks;
|
||||
|
||||
/* The tick hook gets called at regular intervals, even if the
|
||||
scheduler is locked. */
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
{
|
||||
vApplicationTickHook();
|
||||
}
|
||||
#endif
|
||||
#if ( CONFIG_FREERTOS_LEGACY_HOOKS == 1 )
|
||||
esp_vApplicationTickHook();
|
||||
#endif /* CONFIG_FREERTOS_LEGACY_HOOKS */
|
||||
}
|
||||
|
||||
#if ( configUSE_PREEMPTION == 1 )
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/* Tests for FreeRTOS task suspend & resume */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
@@ -12,6 +14,11 @@
|
||||
|
||||
#include "driver/timer.h"
|
||||
|
||||
#include "esp_ipc.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
|
||||
/* Counter task counts a target variable forever */
|
||||
static void task_count(void *vp_counter)
|
||||
{
|
||||
@@ -171,4 +178,189 @@ TEST_CASE("Resume task from ISR (other core)", "[freertos]")
|
||||
{
|
||||
test_resume_task_from_isr(!UNITY_FREERTOS_CPU);
|
||||
}
|
||||
#endif
|
||||
|
||||
static volatile bool block;
|
||||
static bool suspend_both_cpus;
|
||||
|
||||
static void IRAM_ATTR suspend_scheduler_while_block_set(void* arg)
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
|
||||
while (block) { };
|
||||
ets_delay_us(1);
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
static void IRAM_ATTR suspend_scheduler_on_both_cpus()
|
||||
{
|
||||
block = true;
|
||||
if (suspend_both_cpus) {
|
||||
TEST_ESP_OK(esp_ipc_call((xPortGetCoreID() == 0) ? 1 : 0, &suspend_scheduler_while_block_set, NULL));
|
||||
}
|
||||
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
|
||||
static void IRAM_ATTR resume_scheduler_on_both_cpus()
|
||||
{
|
||||
block = false;
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
static const int waiting_ms = 2000;
|
||||
static const int delta_ms = 100;
|
||||
static int duration_wait_task_ms;
|
||||
static int duration_ctrl_task_ms;
|
||||
|
||||
static void waiting_task(void *pvParameters)
|
||||
{
|
||||
int cpu_id = xPortGetCoreID();
|
||||
int64_t start_time = esp_timer_get_time();
|
||||
printf("Start waiting_task cpu=%d\n", cpu_id);
|
||||
|
||||
vTaskDelay(waiting_ms / portTICK_PERIOD_MS);
|
||||
|
||||
duration_wait_task_ms = (esp_timer_get_time() - start_time) / 1000;
|
||||
printf("Finish waiting_task cpu=%d, time=%d ms\n", cpu_id, duration_wait_task_ms);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void control_task(void *pvParameters)
|
||||
{
|
||||
int cpu_id = xPortGetCoreID();
|
||||
ets_delay_us(2000); // let to start the waiting_task first
|
||||
printf("Start control_task cpu=%d\n", cpu_id);
|
||||
int64_t start_time = esp_timer_get_time();
|
||||
|
||||
suspend_scheduler_on_both_cpus();
|
||||
ets_delay_us(waiting_ms * 1000 + delta_ms * 1000);
|
||||
resume_scheduler_on_both_cpus();
|
||||
|
||||
duration_ctrl_task_ms = (esp_timer_get_time() - start_time) / 1000;
|
||||
printf("Finish control_task cpu=%d, time=%d ms\n", cpu_id, duration_ctrl_task_ms);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void test_scheduler_suspend1(int cpu)
|
||||
{
|
||||
/* This test tests a case then both CPUs were in suspend state and then resume CPUs back.
|
||||
* A task for which a wait time has been set and this time has elapsed in the suspended state should in any case be ready to start.
|
||||
* (In an old implementation of xTaskIncrementTick function the counting for waiting_task() will be continued
|
||||
* (excluding time in suspended) after control_task() is finished.)
|
||||
*/
|
||||
duration_wait_task_ms = 0;
|
||||
duration_ctrl_task_ms = 0;
|
||||
|
||||
printf("Test for CPU%d\n", cpu);
|
||||
int other_cpu = (cpu == 0) ? 1 : 0;
|
||||
xTaskCreatePinnedToCore(&waiting_task, "waiting_task", 8192, NULL, 5, NULL, other_cpu);
|
||||
xTaskCreatePinnedToCore(&control_task, "control_task", 8192, NULL, 5, NULL, cpu);
|
||||
|
||||
vTaskDelay(waiting_ms * 2 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT_INT_WITHIN(4, waiting_ms + delta_ms + 4, duration_ctrl_task_ms);
|
||||
if (suspend_both_cpus == false && cpu == 1) {
|
||||
// CPU0 continues to increase the TickCount and the wait_task does not depend on Suspended Scheduler on CPU1
|
||||
TEST_ASSERT_INT_WITHIN(2, waiting_ms, duration_wait_task_ms);
|
||||
} else {
|
||||
TEST_ASSERT_INT_WITHIN(4, waiting_ms + delta_ms + 4, duration_wait_task_ms);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
TEST_CASE("Test the waiting task not missed due to scheduler suspension on both CPUs", "[freertos]")
|
||||
{
|
||||
printf("Suspend both CPUs:\n");
|
||||
suspend_both_cpus = true;
|
||||
test_scheduler_suspend1(0);
|
||||
test_scheduler_suspend1(1);
|
||||
}
|
||||
|
||||
TEST_CASE("Test the waiting task not missed due to scheduler suspension on one CPU", "[freertos]")
|
||||
{
|
||||
printf("Suspend only one CPU:\n");
|
||||
suspend_both_cpus = false;
|
||||
test_scheduler_suspend1(0);
|
||||
test_scheduler_suspend1(1);
|
||||
}
|
||||
|
||||
static uint32_t count_tick[2];
|
||||
|
||||
static void IRAM_ATTR tick_hook()
|
||||
{
|
||||
++count_tick[xPortGetCoreID()];
|
||||
}
|
||||
|
||||
static void test_scheduler_suspend2(int cpu)
|
||||
{
|
||||
esp_register_freertos_tick_hook_for_cpu(tick_hook, 0);
|
||||
esp_register_freertos_tick_hook_for_cpu(tick_hook, 1);
|
||||
|
||||
memset(count_tick, 0, sizeof(count_tick));
|
||||
|
||||
printf("Test for CPU%d\n", cpu);
|
||||
xTaskCreatePinnedToCore(&control_task, "control_task", 8192, NULL, 5, NULL, cpu);
|
||||
|
||||
vTaskDelay(waiting_ms * 2 / portTICK_PERIOD_MS);
|
||||
esp_deregister_freertos_tick_hook(tick_hook);
|
||||
|
||||
printf("count_tick[cpu0] = %d, count_tick[cpu1] = %d\n", count_tick[0], count_tick[1]);
|
||||
|
||||
TEST_ASSERT_INT_WITHIN(1, waiting_ms * 2, count_tick[0]);
|
||||
TEST_ASSERT_INT_WITHIN(1, waiting_ms * 2, count_tick[1]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
TEST_CASE("Test suspend-resume CPU. The number of tick_hook should be the same for both CPUs", "[freertos]")
|
||||
{
|
||||
printf("Suspend both CPUs:\n");
|
||||
suspend_both_cpus = true;
|
||||
test_scheduler_suspend2(0);
|
||||
test_scheduler_suspend2(1);
|
||||
|
||||
printf("Suspend only one CPU:\n");
|
||||
suspend_both_cpus = false;
|
||||
test_scheduler_suspend2(0);
|
||||
test_scheduler_suspend2(1);
|
||||
}
|
||||
|
||||
static int duration_timer_ms;
|
||||
|
||||
static void timer_callback(void *arg)
|
||||
{
|
||||
++duration_timer_ms;
|
||||
}
|
||||
|
||||
static void test_scheduler_suspend3(int cpu)
|
||||
{
|
||||
duration_timer_ms = 0;
|
||||
duration_ctrl_task_ms = 0;
|
||||
|
||||
printf("Test for CPU%d\n", cpu);
|
||||
TimerHandle_t count_time = xTimerCreate("count_time", 1, pdTRUE, NULL, timer_callback);
|
||||
xTimerStart( count_time, portMAX_DELAY);
|
||||
xTaskCreatePinnedToCore(&control_task, "control_task", 8192, NULL, 5, NULL, cpu);
|
||||
|
||||
vTaskDelay(waiting_ms * 2 / portTICK_PERIOD_MS);
|
||||
xTimerDelete(count_time, portMAX_DELAY);
|
||||
printf("Finish duration_timer_ms=%d ms\n", duration_timer_ms);
|
||||
|
||||
TEST_ASSERT_INT_WITHIN(2, waiting_ms * 2, duration_timer_ms);
|
||||
TEST_ASSERT_INT_WITHIN(5, waiting_ms + delta_ms, duration_ctrl_task_ms);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
TEST_CASE("Test suspend-resume CPU works with xTimer", "[freertos]")
|
||||
{
|
||||
printf("Suspend both CPUs:\n");
|
||||
suspend_both_cpus = true;
|
||||
test_scheduler_suspend3(0);
|
||||
test_scheduler_suspend3(1);
|
||||
|
||||
printf("Suspend only one CPU:\n");
|
||||
suspend_both_cpus = false;
|
||||
test_scheduler_suspend3(0);
|
||||
test_scheduler_suspend3(1);
|
||||
}
|
||||
#endif // CONFIG_FREERTOS_UNICORE
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
__all__ = ["UnitTest"]
|
||||
@@ -1,292 +0,0 @@
|
||||
test environment:
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_1,
|
||||
test environment detail: 'PC has 2 wired NIC connected to AP.
|
||||
|
||||
PC has 1 WiFi NIC.
|
||||
|
||||
1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_2,
|
||||
test environment detail: 'PC has 1 WiFi NIC.
|
||||
|
||||
1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_3,
|
||||
test environment detail: 'Able to access WAN after connect to AP.
|
||||
|
||||
1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_ADC,
|
||||
test environment detail: 'PC has 1 wired NIC connected to AP.
|
||||
|
||||
Analog input connect to AT1 TOUT.
|
||||
|
||||
Multimeter connect to input, able to measure input voltage.
|
||||
|
||||
1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC1,
|
||||
test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\
|
||||
\ connected to APC (static IP within the same subnet with APC). \nAPC control\
|
||||
\ AP power supply. \nPC has 1 WiFi NIC. \n1 AT target connect with PC by UART\
|
||||
\ (AT and LOG port).", test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC2,
|
||||
test environment detail: "Able to access WAN after connect to AP.\nPC has 1 wired\
|
||||
\ NIC connected to APC (static IP within the same subnet with APC). \nAPC control\
|
||||
\ AP power supply.\nPC has 1 WiFi NIC.\n1 AT target connect with PC by UART (AT\
|
||||
\ and LOG port).", test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_HighSpeedUART,
|
||||
test environment detail: 'PC has 2 wired NIC connected to AP.
|
||||
|
||||
PC has 1 WiFi NIC.
|
||||
|
||||
1 AT target connect with PC by high speed UART (AT and LOG port).', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_SmartConfigIOT,
|
||||
test environment detail: '1 AT target connect with PC by UART (AT and LOG port).
|
||||
|
||||
PC has 1 wired NIC connect to Common AP.
|
||||
|
||||
Several AP are placed near AT target.
|
||||
|
||||
Several smart phone installed test APK are placed near AT target.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_1,
|
||||
test environment detail: 'PC has 1 wired NIC connected to AP.
|
||||
|
||||
PC has 1 WiFi NIC.
|
||||
|
||||
2 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_JAP,
|
||||
test environment detail: "Several AP are placed near AT target.\nPC has 1 wired\
|
||||
\ NIC connected to APC (static IP within the same subnet with APC).\nAPC control\
|
||||
\ power supply for all APs. \n2 AT target connect with PC by UART (AT and LOG\
|
||||
\ port).", test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_Sleep,
|
||||
test environment detail: 'AP support DTIM placed with AT target.
|
||||
|
||||
2 AT target connect with PC by UART (AT and LOG port).
|
||||
|
||||
Multimeter connect with PC via GPIB.
|
||||
|
||||
Series multimeter between GND and VCC of AT1.
|
||||
|
||||
AT1''s light sleep wakeup pin and wakeup indication connect with AT2''s GPIO.',
|
||||
test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_SmartConfig,
|
||||
test environment detail: '2 AT target connect with PC by UART (AT and LOG port).
|
||||
|
||||
PC has 1 WiFi NIC.
|
||||
|
||||
One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1
|
||||
|
||||
SSC2', additional param list: '', basic param list: '', script path: EnvBase.py,
|
||||
tag: IR_T2_1, test environment detail: '[TBD] 本测试为非自动测试, 红外能够做到数据收发吻合即可通过', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: NVS_T1_1,
|
||||
test environment detail: '1 NVS target connect with PC by UART.
|
||||
|
||||
1 SSC target connect with PC by UART.
|
||||
|
||||
SSC2 GPIO connect to NVS1 power control pin.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '',
|
||||
basic param list: '', script path: EnvBase.py, tag: PWM_T1_1, test environment detail: "[TBD]\
|
||||
\ 1. PWM OS SDK 以及 Non-OS SDK的测试建议分开进行, 放在不同的文件夹, 防止文件命名混淆\n2. 分析CSV文件的Python脚本只能分析单个channel\
|
||||
\ \n3. 如果Init脚本打印\"Network Error\" 检查TCP Server是不是正常发送data", test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_1,
|
||||
test environment detail: 'PC has 2 wired NIC connected to AP.
|
||||
|
||||
PC has 1 WiFi NIC.
|
||||
|
||||
1 SSC target connect with PC by UART.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_2,
|
||||
test environment detail: 'Able to access WAN after connect to AP.
|
||||
|
||||
1 SSC target connect with PC by UART.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_8089,
|
||||
test environment detail: 'PC has 1 wired NIC connected to AP.
|
||||
|
||||
1 8089 tablet able to run iperf test placed near SSC1.
|
||||
|
||||
1 SSC target connect with PC by UART.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ADC,
|
||||
test environment detail: 'PC has 1 wired NIC connected to AP.
|
||||
|
||||
Analog input connect to SSC1 TOUT.
|
||||
|
||||
Multimeter connect to input, able to measure input voltage.
|
||||
|
||||
1 SSC target connect with PC by UART.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_APC,
|
||||
test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\
|
||||
\ connected to APC (static IP within the same subnet with APC). \nAPC control\
|
||||
\ AP power supply. \nPC has 1 WiFi NIC. \n1 SSC target connect with PC by UART.",
|
||||
test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Enterprise,
|
||||
test environment detail: "AP use WPA2-Etherprise is placed near SSC1. \n1 SSC target\
|
||||
\ connect with PC by UART.", test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_IOT1,
|
||||
test environment detail: 'PC has 1 WiFi NIC.
|
||||
|
||||
1 SSC target connect with PC by UART.
|
||||
|
||||
AP todo IOT test are placed near SSC1.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T1_InitData,
|
||||
test environment detail: '2 SSC target connect with PC by UART.
|
||||
|
||||
SSC1 use 40M crystal oscillator.
|
||||
|
||||
SSC2 use normal 26M crystal oscillator.
|
||||
|
||||
SSC2 GPIO connect to SSC1 power control pin.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ShieldBox,
|
||||
test environment detail: 'refer to figure.
|
||||
|
||||
All APs and APC should be set to the same IP subnet.
|
||||
|
||||
PC wired NIC should set static IP address within the same subnet with AP.
|
||||
|
||||
Must use onboard wired NIC.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep1,
|
||||
test environment detail: 'AP support DTIM placed with AT target.
|
||||
|
||||
SSC target connect with Raspberry Pi by UART.
|
||||
|
||||
Multimeter connect with Raspberry Pi via GPIB.
|
||||
|
||||
Series multimeter between GND and VCC of SSC1.
|
||||
|
||||
SSC1''s light sleep wakeup pin and wakeup indication connect with Raspberry Pi''s
|
||||
GPIO.
|
||||
|
||||
SSC1''s XPD connect with RSTB.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep2,
|
||||
test environment detail: 'AP support DTIM placed with AT target.
|
||||
|
||||
SSC target connect with Raspberry Pi by UART.
|
||||
|
||||
Multimeter connect with Raspberry Pi via GPIB.
|
||||
|
||||
Series multimeter between GND and VCC of SSC1.
|
||||
|
||||
SSC1''s RSTB pin connect with Raspberry Pi''s GPIO.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_TempBox,
|
||||
test environment detail: '1 SSC target connect with PC by UART.
|
||||
|
||||
Put SSC target to temperature box.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '',
|
||||
basic param list: '', script path: EnvBase.py, tag: SSC_T1_Timer, test environment detail: '[TBD]
|
||||
通过串口工具调节Timer, 将GPIO_13端口连接到逻辑分析仪', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_VDD33,
|
||||
test environment detail: '1 SSC target connect with PC by UART.
|
||||
|
||||
Multimeter connect to VDD33, able to measure voltage.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_WEP,
|
||||
test environment detail: '1 SSC target connect with PC by UART.
|
||||
|
||||
One WEP share key AP placed near SSC1.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_1,
|
||||
test environment detail: 'PC has 1 wired NIC connected to AP.
|
||||
|
||||
PC has 1 WiFi NIC.
|
||||
|
||||
2 SSC target connect with PC by UART.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1
|
||||
|
||||
SSC2', additional param list: '', basic param list: '', script path: EnvBase.py,
|
||||
tag: SSC_T2_GPIO1, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266的
|
||||
GPIO_6相连', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1
|
||||
|
||||
SSC2', additional param list: '', basic param list: '', script path: EnvBase.py,
|
||||
tag: SSC_T2_GPIO2, test environment detail: '[TBD] 1. 2个ESP_8266通过UART连到PC, ESP_8266的
|
||||
GPIO_15通过面包板相连
|
||||
|
||||
2. 可借助面包板, 将GPIO_15, 以及中断函数被打开的8266板的GPIO_2 相连', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1
|
||||
|
||||
SSC2', additional param list: '', basic param list: '', script path: EnvBase.py,
|
||||
tag: SSC_T2_GPIO3, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266之间需要测试的Target_GPIO相连',
|
||||
test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_JAP,
|
||||
test environment detail: 'PC has 1 wired NIC connected to APC.
|
||||
|
||||
APC control the power supply of multiple APs.
|
||||
|
||||
2 SSC target connect with PC by UART.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_PhyMode,
|
||||
test environment detail: '2 SSC target connect with PC by UART.
|
||||
|
||||
PC has one WiFi NIC support capture wlan packet using libpcap.
|
||||
|
||||
Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40.
|
||||
|
||||
Put 4 APs near SSC targets.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_ShieldBox,
|
||||
test environment detail: '2 SSC target connect with PC by UART.
|
||||
|
||||
Put them to Shield box.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_SmartConfig,
|
||||
test environment detail: '2 SSC target connect with PC by UART.
|
||||
|
||||
PC has 1 WiFi NIC.
|
||||
|
||||
One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 3.0, script path: EnvBase.py, tag: SSC_T3_PhyMode,
|
||||
test environment detail: '3 SSC target connect with PC by UART.
|
||||
|
||||
PC has one WiFi NIC support capture wlan packet using libpcap.
|
||||
|
||||
Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2).
|
||||
|
||||
Put 4 APs near SSC targets.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_1,
|
||||
test environment detail: 5 SSC target connect with PC by UART., test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_IOT1,
|
||||
test environment detail: '5 SSC targets connect with PC by UART.
|
||||
|
||||
some Android smart phone are placed near SSC targets.', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T6_1,
|
||||
test environment detail: 'PC has 1 wired NIC connected to AP.
|
||||
|
||||
PC has 1 WiFi NIC.
|
||||
|
||||
6 SSC target connect with PC by UART.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: TempSensor_T1_1,
|
||||
test environment detail: 'Tempeture sensor target connect with PC by UART.
|
||||
|
||||
AP support DTIM placed with AT target.
|
||||
|
||||
Multimeter connect with PC via GPIB.
|
||||
|
||||
Series multimeter between GND and VCC of TempSensor1.
|
||||
|
||||
PC has 1 wired NIC connected to switch.
|
||||
|
||||
APC, AP also connect with swtich.
|
||||
|
||||
All devices connected with switch use the same IP subnet.
|
||||
|
||||
APC control AP power supply.', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '',
|
||||
basic param list: '', script path: EnvBase.py, tag: UART_T1_1, test environment detail: '[TBD]
|
||||
将ESP_8266通过UART连到PC', test script: EnvBase}
|
||||
- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1
|
||||
|
||||
SSC2', additional param list: '', basic param list: '', script path: EnvBase.py,
|
||||
tag: UART_T1_2, test environment detail: '[TBD] ESP_8266通过UART_0通过USB, UART_1 TXD
|
||||
通过 TTLcable 连到PC', test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_1,
|
||||
test environment detail: Environment for running ESP32 unit tests, test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_SDMODE,
|
||||
test environment detail: Environment for running sd card sd mode unit tests, test script: EnvBase}
|
||||
- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_SPIMODE,
|
||||
test environment detail: Environment for running sd card spi mode unit tests, test script: EnvBase}
|
||||
- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_1,
|
||||
test environment detail: 'Web Server target connect with PC by UART.
|
||||
|
||||
PC has 1 wired NIC connected to switch.
|
||||
|
||||
APC, AP also connect with swtich.
|
||||
|
||||
All devices connected with switch use same IP subnet.
|
||||
|
||||
APC control AP power supply.', test script: EnvBase}
|
||||
- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_2,
|
||||
test environment detail: 'Web Server target connect with PC by UART.
|
||||
|
||||
4 PC with WiFi NIC placed near WebServer1.', test script: EnvBase}
|
||||
@@ -48,7 +48,7 @@ extern "C" {
|
||||
// After completing read operations, use DPORT_STALL_OTHER_CPU_END().
|
||||
// This method uses stall other CPU while reading DPORT registers.
|
||||
// Useful for compatibility, as well as for large consecutive readings.
|
||||
// This method is slower, but must be used if ROM functions or
|
||||
// This method is slower, but must be used if ROM functions or
|
||||
// other code is called which accesses DPORT without any other workaround.
|
||||
// *) The pre-readable APB register before reading the DPORT register
|
||||
// helps synchronize the operation of the two CPUs,
|
||||
@@ -73,7 +73,7 @@ extern "C" {
|
||||
*/
|
||||
static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
return esp_dport_access_reg_read(reg);
|
||||
@@ -106,7 +106,7 @@ static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg)
|
||||
*/
|
||||
static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
return esp_dport_access_sequence_reg_read(reg);
|
||||
@@ -166,7 +166,7 @@ static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg)
|
||||
*/
|
||||
static inline uint32_t IRAM_ATTR DPORT_READ_PERI_REG(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
return esp_dport_access_reg_read(reg);
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
|
||||
#define IS_DPORT_REG(_r) (((_r) >= DR_REG_DPORT_BASE) && (_r) <= DR_REG_DPORT_END)
|
||||
|
||||
#if !defined( BOOTLOADER_BUILD ) && !defined( CONFIG_FREERTOS_UNICORE ) && defined( ESP_PLATFORM )
|
||||
#if !defined( BOOTLOADER_BUILD ) && defined( CONFIG_ESP32_DPORT_WORKAROUND ) && defined( ESP_PLATFORM )
|
||||
#define ASSERT_IF_DPORT_REG(_r, OP) TRY_STATIC_ASSERT(!IS_DPORT_REG(_r), (Cannot use OP for DPORT registers use DPORT_##OP));
|
||||
#else
|
||||
#define ASSERT_IF_DPORT_REG(_r, OP)
|
||||
|
||||
@@ -48,9 +48,6 @@ die() {
|
||||
|
||||
echo "build_examples running in ${PWD}"
|
||||
|
||||
# only 0 or 1 arguments
|
||||
[ $# -le 1 ] || die "Have to run as $(basename $0) [<JOB_NAME>]"
|
||||
|
||||
export BATCH_BUILD=1
|
||||
export V=0 # only build verbose if there's an error
|
||||
|
||||
@@ -65,26 +62,14 @@ SDKCONFIG_DEFAULTS_CI=sdkconfig.ci
|
||||
|
||||
EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name Makefile | grep -v "/build_system/cmake/" | sort )
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
if [ -z "${CI_NODE_TOTAL:-}" ]
|
||||
then
|
||||
START_NUM=0
|
||||
END_NUM=999
|
||||
else
|
||||
JOB_NAME=$1
|
||||
|
||||
# parse text prefix at the beginning of string 'some_your_text_NUM'
|
||||
# (will be 'some_your_text' without last '_')
|
||||
JOB_PATTERN=$( echo ${JOB_NAME} | sed -n -r 's/^(.*)_[0-9]+$/\1/p' )
|
||||
[ -z ${JOB_PATTERN} ] && die "JOB_PATTERN is bad"
|
||||
|
||||
# parse number 'NUM' at the end of string 'some_your_text_NUM'
|
||||
# NOTE: Getting rid of the leading zero to get the decimal
|
||||
JOB_NUM=$( echo ${JOB_NAME} | sed -n -r 's/^.*_0*([0-9]+)$/\1/p' )
|
||||
[ -z ${JOB_NUM} ] && die "JOB_NUM is bad"
|
||||
|
||||
JOB_NUM=${CI_NODE_INDEX}
|
||||
# count number of the jobs
|
||||
NUM_OF_JOBS=$( grep -c -E "^${JOB_PATTERN}_[0-9]+:$" "${IDF_PATH}/.gitlab-ci.yml" )
|
||||
[ -z ${NUM_OF_JOBS} ] && die "NUM_OF_JOBS is bad"
|
||||
NUM_OF_JOBS=${CI_NODE_TOTAL}
|
||||
|
||||
# count number of examples
|
||||
NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l )
|
||||
@@ -96,10 +81,10 @@ else
|
||||
[ -z ${NUM_OF_EX_PER_JOB} ] && die "NUM_OF_EX_PER_JOB is bad"
|
||||
|
||||
# ex.: [0; 12); [12; 24); [24; 36); [36; 48); [48; 60)
|
||||
START_NUM=$(( ${JOB_NUM} * ${NUM_OF_EX_PER_JOB} ))
|
||||
START_NUM=$(( (${JOB_NUM} - 1) * ${NUM_OF_EX_PER_JOB} ))
|
||||
[ -z ${START_NUM} ] && die "START_NUM is bad"
|
||||
|
||||
END_NUM=$(( (${JOB_NUM} + 1) * ${NUM_OF_EX_PER_JOB} ))
|
||||
END_NUM=$(( ${JOB_NUM} * ${NUM_OF_EX_PER_JOB} ))
|
||||
[ -z ${END_NUM} ] && die "END_NUM is bad"
|
||||
fi
|
||||
|
||||
@@ -168,6 +153,8 @@ build_example () {
|
||||
|
||||
EXAMPLE_NUM=0
|
||||
|
||||
echo "Current job will build example ${START_NUM} - ${END_NUM}"
|
||||
|
||||
for EXAMPLE_PATH in ${EXAMPLE_PATHS}
|
||||
do
|
||||
if [[ $EXAMPLE_NUM -lt $START_NUM || $EXAMPLE_NUM -ge $END_NUM ]]
|
||||
|
||||
@@ -68,26 +68,14 @@ SDKCONFIG_DEFAULTS_CI=sdkconfig.ci
|
||||
|
||||
EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/main/" | sort )
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
if [ -z "${CI_NODE_TOTAL:-}" ]
|
||||
then
|
||||
START_NUM=0
|
||||
END_NUM=999
|
||||
else
|
||||
JOB_NAME=$1
|
||||
|
||||
# parse text prefix at the beginning of string 'some_your_text_NUM'
|
||||
# (will be 'some_your_text' without last '_')
|
||||
JOB_PATTERN=$( echo ${JOB_NAME} | sed -n -r 's/^(.*)_[0-9]+$/\1/p' )
|
||||
[ -z ${JOB_PATTERN} ] && die "JOB_PATTERN is bad"
|
||||
|
||||
# parse number 'NUM' at the end of string 'some_your_text_NUM'
|
||||
# NOTE: Getting rid of the leading zero to get the decimal
|
||||
JOB_NUM=$( echo ${JOB_NAME} | sed -n -r 's/^.*_0*([0-9]+)$/\1/p' )
|
||||
[ -z ${JOB_NUM} ] && die "JOB_NUM is bad"
|
||||
|
||||
JOB_NUM=${CI_NODE_INDEX}
|
||||
# count number of the jobs
|
||||
NUM_OF_JOBS=$( grep -c -E "^${JOB_PATTERN}_[0-9]+:$" "${IDF_PATH}/.gitlab-ci.yml" )
|
||||
[ -z ${NUM_OF_JOBS} ] && die "NUM_OF_JOBS is bad"
|
||||
NUM_OF_JOBS=${CI_NODE_TOTAL}
|
||||
|
||||
# count number of examples
|
||||
NUM_OF_EXAMPLES=$( echo "${EXAMPLE_PATHS}" | wc -l )
|
||||
@@ -99,10 +87,10 @@ else
|
||||
[ -z ${NUM_OF_EX_PER_JOB} ] && die "NUM_OF_EX_PER_JOB is bad"
|
||||
|
||||
# ex.: [0; 12); [12; 24); [24; 36); [36; 48); [48; 60)
|
||||
START_NUM=$(( ${JOB_NUM} * ${NUM_OF_EX_PER_JOB} ))
|
||||
START_NUM=$(( (${JOB_NUM} - 1) * ${NUM_OF_EX_PER_JOB} ))
|
||||
[ -z ${START_NUM} ] && die "START_NUM is bad"
|
||||
|
||||
END_NUM=$(( (${JOB_NUM} + 1) * ${NUM_OF_EX_PER_JOB} ))
|
||||
END_NUM=$(( ${JOB_NUM} * ${NUM_OF_EX_PER_JOB} ))
|
||||
[ -z ${END_NUM} ] && die "END_NUM is bad"
|
||||
fi
|
||||
|
||||
@@ -156,6 +144,8 @@ build_example () {
|
||||
|
||||
EXAMPLE_NUM=0
|
||||
|
||||
echo "Current job will build example ${START_NUM} - ${END_NUM}"
|
||||
|
||||
for EXAMPLE_PATH in ${EXAMPLE_PATHS}
|
||||
do
|
||||
if [[ $EXAMPLE_NUM -lt $START_NUM || $EXAMPLE_NUM -ge $END_NUM ]]
|
||||
|
||||
@@ -380,6 +380,41 @@ EOF
|
||||
|| failure "ccache should not be used even when present if --no-ccache is specified"
|
||||
rm -f ccache
|
||||
|
||||
print_status "Empty directory not treated as a component"
|
||||
clean_build_dir
|
||||
mkdir -p components/esp32 && idf.py reconfigure
|
||||
! grep "$PWD/components/esp32" $PWD/build/project_description.json || failure "Failed to build with empty esp32 directory in components"
|
||||
rm -rf components
|
||||
|
||||
print_status "If a component directory is added to COMPONENT_DIRS, its subdirectories are not added"
|
||||
clean_build_dir
|
||||
mkdir -p main/test
|
||||
echo "register_component()" > main/test/CMakeLists.txt
|
||||
idf.py reconfigure
|
||||
! grep "$PWD/main/test" $PWD/build/project_description.json || failure "COMPONENT_DIRS has added component subdirectory to the build"
|
||||
grep "$PWD/main" $PWD/build/project_description.json || failure "COMPONENT_DIRS parent component directory should be included in the build"
|
||||
rm -rf main/test
|
||||
|
||||
print_status "If a component directory is added to COMPONENT_DIRS, its sibling directories are not added"
|
||||
clean_build_dir
|
||||
mkdir -p mycomponents/mycomponent
|
||||
echo "register_component()" > mycomponents/mycomponent/CMakeLists.txt
|
||||
# first test by adding single component directory to EXTRA_COMPONENT_DIRS
|
||||
mkdir -p mycomponents/esp32
|
||||
echo "register_component()" > mycomponents/esp32/CMakeLists.txt
|
||||
idf.py reconfigure -DEXTRA_COMPONENT_DIRS=$PWD/mycomponents/mycomponent
|
||||
! grep "$PWD/mycomponents/esp32" $PWD/build/project_description.json || failure "EXTRA_COMPONENT_DIRS has added a sibling directory"
|
||||
grep "$PWD/mycomponents/mycomponent" $PWD/build/project_description.json || failure "EXTRA_COMPONENT_DIRS valid sibling directory should be in the build"
|
||||
rm -rf mycomponents/esp32
|
||||
# now the same thing, but add a components directory
|
||||
mkdir -p esp32
|
||||
echo "register_component()" > esp32/CMakeLists.txt
|
||||
idf.py reconfigure -DEXTRA_COMPONENT_DIRS=$PWD/mycomponents
|
||||
! grep "$PWD/esp32" $PWD/build/project_description.json || failure "EXTRA_COMPONENT_DIRS has added a sibling directory"
|
||||
grep "$PWD/mycomponents/mycomponent" $PWD/build/project_description.json || failure "EXTRA_COMPONENT_DIRS valid sibling directory should be in the build"
|
||||
rm -rf esp32
|
||||
rm -rf mycomponents
|
||||
|
||||
print_status "All tests completed"
|
||||
if [ -n "${FAILURES}" ]; then
|
||||
echo "Some failures were detected:"
|
||||
|
||||
@@ -28,49 +28,47 @@ endfunction()
|
||||
# earlier in the component_dirs list take precedence.
|
||||
function(components_find_all component_dirs component_paths component_names test_component_names)
|
||||
# component_dirs entries can be files or lists of files
|
||||
set(paths "")
|
||||
set(names "")
|
||||
set(test_names "")
|
||||
set(_paths "")
|
||||
set(_names "")
|
||||
set(_test_names "")
|
||||
|
||||
# start by expanding the component_dirs list with all subdirectories
|
||||
foreach(dir ${component_dirs})
|
||||
# Iterate any subdirectories for values
|
||||
file(GLOB subdirs LIST_DIRECTORIES true "${dir}/*")
|
||||
foreach(subdir ${subdirs})
|
||||
set(component_dirs "${component_dirs};${subdir}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Look for a component in each component_dirs entry
|
||||
foreach(dir ${component_dirs})
|
||||
debug("Looking for CMakeLists.txt in ${dir}")
|
||||
file(GLOB component "${dir}/CMakeLists.txt")
|
||||
if(component)
|
||||
debug("CMakeLists.txt file ${component}")
|
||||
get_filename_component(component "${component}" DIRECTORY)
|
||||
get_filename_component(name "${component}" NAME)
|
||||
if(EXISTS ${dir}/CMakeLists.txt)
|
||||
get_filename_component(_path "${dir}" ABSOLUTE)
|
||||
get_filename_component(_name "${_path}" NAME)
|
||||
if(NOT name IN_LIST names)
|
||||
list(APPEND names "${name}")
|
||||
list(APPEND paths "${component}")
|
||||
|
||||
# Look for test component directory
|
||||
file(GLOB test "${component}/test/CMakeLists.txt")
|
||||
if(test)
|
||||
list(APPEND test_names "${name}")
|
||||
endif()
|
||||
list(APPEND _names "${_name}")
|
||||
list(APPEND _paths "${_path}")
|
||||
endif()
|
||||
else() # no CMakeLists.txt file
|
||||
# test for legacy component.mk and warn
|
||||
file(GLOB legacy_component "${dir}/component.mk")
|
||||
if(legacy_component)
|
||||
|
||||
if(EXISTS "${_path}/test/CMakeLists.txt")
|
||||
list(APPEND _test_names "${_name}")
|
||||
endif()
|
||||
else()
|
||||
if(EXISTS ${dir}/component.mk)
|
||||
get_filename_component(legacy_component "${legacy_component}" DIRECTORY)
|
||||
message(WARNING "Component ${legacy_component} contains old-style component.mk but no CMakeLists.txt. "
|
||||
"Component will be skipped.")
|
||||
else()
|
||||
if(NOT __recursing) # recurse only once
|
||||
file(GLOB subdirs LIST_DIRECTORIES true "${dir}/*")
|
||||
|
||||
set(__recursing 1)
|
||||
components_find_all("${subdirs}" __paths __names __test_names)
|
||||
set(__recursing 0)
|
||||
|
||||
if(__paths)
|
||||
list(APPEND _paths "${__paths}")
|
||||
list(APPEND _names "${__names}")
|
||||
list(APPEND _test_names "${__test_names}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${component_paths} ${paths} PARENT_SCOPE)
|
||||
set(${component_names} ${names} PARENT_SCOPE)
|
||||
set(${test_component_names} ${test_names} PARENT_SCOPE)
|
||||
set(${test_component_names} "${_test_names}" PARENT_SCOPE)
|
||||
set(${component_paths} "${_paths}" PARENT_SCOPE)
|
||||
set(${component_names} "${_names}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -108,8 +108,11 @@ function(register_component)
|
||||
endforeach()
|
||||
|
||||
if(${COMPONENT_NAME} IN_LIST BUILD_TEST_COMPONENTS)
|
||||
target_link_libraries(${COMPONENT_TARGET} "-L${CMAKE_CURRENT_BINARY_DIR}")
|
||||
target_link_libraries(${COMPONENT_TARGET} "-Wl,--whole-archive -l${COMPONENT_NAME} -Wl,--no-whole-archive")
|
||||
set_property(TARGET ${IDF_PROJECT_EXECUTABLE} APPEND PROPERTY
|
||||
LINK_LIBRARIES "-L${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
set_property(TARGET ${IDF_PROJECT_EXECUTABLE} APPEND PROPERTY
|
||||
LINK_LIBRARIES "-Wl,--whole-archive -l${COMPONENT_NAME} -Wl,--no-whole-archive")
|
||||
endif()
|
||||
|
||||
if(COMPONENT_SRCS OR embed_binaries)
|
||||
|
||||
@@ -134,6 +134,19 @@ class AssignTest(object):
|
||||
self.jobs = self._parse_gitlab_ci_config(ci_config_file)
|
||||
self.case_group = case_group
|
||||
|
||||
@staticmethod
|
||||
def _handle_parallel_attribute(job_name, job):
|
||||
jobs_out = []
|
||||
try:
|
||||
for i in range(job["parallel"]):
|
||||
jobs_out.append(GitlabCIJob.Job(job, job_name + "_{}".format(i + 1)))
|
||||
except KeyError:
|
||||
# Gitlab don't allow to set parallel to 1.
|
||||
# to make test job name same ($CI_JOB_NAME_$CI_NODE_INDEX),
|
||||
# we append "_" to jobs don't have parallel attribute
|
||||
jobs_out.append(GitlabCIJob.Job(job, job_name + "_"))
|
||||
return jobs_out
|
||||
|
||||
def _parse_gitlab_ci_config(self, ci_config_file):
|
||||
|
||||
with open(ci_config_file, "r") as f:
|
||||
@@ -142,7 +155,7 @@ class AssignTest(object):
|
||||
job_list = list()
|
||||
for job_name in ci_config:
|
||||
if self.CI_TEST_JOB_PATTERN.search(job_name) is not None:
|
||||
job_list.append(GitlabCIJob.Job(ci_config[job_name], job_name))
|
||||
job_list.extend(self._handle_parallel_attribute(job_name, ci_config[job_name]))
|
||||
job_list.sort(key=lambda x: x["name"])
|
||||
return job_list
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ TEST_CASE_PATTERN = {
|
||||
class Parser(object):
|
||||
""" parse unit test cases from build files and create files for test bench """
|
||||
|
||||
TAG_PATTERN = re.compile("([^=]+)(=)?(.+)?")
|
||||
DESCRIPTION_PATTERN = re.compile("\[([^]\[]+)\]") # noqa: W605 - regular expression
|
||||
TAG_PATTERN = re.compile(r"([^=]+)(=)?(.+)?")
|
||||
DESCRIPTION_PATTERN = re.compile(r"\[([^]\[]+)\]")
|
||||
CONFIG_PATTERN = re.compile(r"{([^}]+)}")
|
||||
TEST_GROUPS_PATTERN = re.compile(r"TEST_GROUPS=(.*)$")
|
||||
|
||||
@@ -261,7 +261,12 @@ class Parser(object):
|
||||
dump parsed test cases to YAML file for test bench input
|
||||
:param test_cases: parsed test cases
|
||||
"""
|
||||
with open(os.path.join(self.idf_path, self.TEST_CASE_FILE), "w+") as f:
|
||||
filename = os.path.join(self.idf_path, self.TEST_CASE_FILE)
|
||||
try:
|
||||
os.mkdir(os.path.dirname(filename))
|
||||
except OSError:
|
||||
pass
|
||||
with open(os.path.join(filename), "w+") as f:
|
||||
yaml.dump({"test cases": test_cases}, f, allow_unicode=True, default_flow_style=False)
|
||||
|
||||
def copy_module_def_file(self):
|
||||
|
||||
Reference in New Issue
Block a user